Cleanup Repos

Add an getViewModelListBehaviorSubject that simplifies
how to get most model lists in the view

unified update, delete and create methods and removed redundant code from the repos
(where it was possible)

cleaned up the motion detail to not directly use the DataStore

Add information about the "main model" to all ViewModels, to call the
correct constructor in the BaseRepo
This commit is contained in:
Sean Engelhardt 2019-03-13 15:16:06 +01:00
parent 74bcc4bcea
commit d4e10702cc
67 changed files with 435 additions and 818 deletions

View File

@ -29,7 +29,7 @@ const routes: Routes = [
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })],
exports: [RouterModule]
})
export class AppRoutingModule {}

View File

@ -28,10 +28,6 @@ export class AuthGuard implements CanActivate, CanActivateChild {
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
const basePerm: string | string[] = route.data.basePerm;
console.log('Auth guard');
console.log('motions.can_see:', this.operator.hasPerms('motions.can_see'));
console.log('motions.can_manage:', this.operator.hasPerms('motions.can_manage'));
if (!basePerm) {
return true;
} else if (basePerm instanceof Array) {

View File

@ -32,6 +32,7 @@ export class DataSendService {
/**
* Function to fully update a model on the server.
* TODO: Deprecated (?)
*
* @param model The model that is meant to be changed.
*/

View File

@ -95,7 +95,6 @@ export class OpenSlidesService {
* @param userId the id or null for guest
*/
public async afterLoginBootup(userId: number | null): Promise<void> {
console.log('user id', userId);
// Check, which user was logged in last time
const lastUserId = await this.storageService.get<number>('lastUserLoggedIn');
// if the user changed, reset the cache and save the new user.

View File

@ -2,22 +2,21 @@ import { Injectable } from '@angular/core';
import { tap, map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
import { BaseRepository } from '../base-repository';
import { BaseAgendaViewModel } from 'app/site/base/base-agenda-view-model';
import { BaseViewModel } from 'app/site/base/base-view-model';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { DataSendService } from 'app/core/core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service';
import { HttpService } from 'app/core/core-services/http.service';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { Item } from 'app/shared/models/agenda/item';
import { OSTreeSortEvent } from 'app/shared/components/sorting-tree/sorting-tree.component';
import { ViewItem } from 'app/site/agenda/models/view-item';
import { TreeService } from 'app/core/ui-services/tree.service';
import { BaseAgendaViewModel } from 'app/site/base/base-agenda-view-model';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { BaseViewModel } from 'app/site/base/base-view-model';
import { TranslateService } from '@ngx-translate/core';
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
import { TreeService } from 'app/core/ui-services/tree.service';
import { ViewItem } from 'app/site/agenda/models/view-item';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
/**
* Repository service for users
@ -42,13 +41,13 @@ export class ItemRepositoryService extends BaseRepository<ViewItem, Item> {
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
protected dataSend: DataSendService,
private httpService: HttpService,
private config: ConfigService,
private dataSend: DataSendService,
private treeService: TreeService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Item);
super(DS, dataSend, mapperService, viewModelStoreService, Item);
}
public getVerboseName = (plural: boolean = false) => {
@ -118,18 +117,6 @@ export class ItemRepositoryService extends BaseRepository<ViewItem, Item> {
}
}
/**
* Updates an agenda item
*
* @param update contains the update data
* @param viewItem the item to update
*/
public async update(update: Partial<Item>, viewItem: ViewItem): Promise<void> {
const updateItem = viewItem.item;
updateItem.patchValues(update);
return await this.dataSend.partialUpdateModel(updateItem);
}
/**
* Trigger the automatic numbering sequence on the server
*/
@ -150,15 +137,6 @@ export class ItemRepositoryService extends BaseRepository<ViewItem, Item> {
await this.httpService.delete(restUrl);
}
/**
* @ignore
*
* Agenda items are created implicitly and do not have on create functions
*/
public async create(item: Item): Promise<Identifiable> {
throw new Error('Method not implemented.');
}
/**
* Get agenda visibility from the config
*

View File

@ -2,19 +2,17 @@ import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Topic } from 'app/shared/models/topics/topic';
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
import { Item } from 'app/shared/models/agenda/item';
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
import { DataStoreService } from 'app/core/core-services/data-store.service';
import { DataSendService } from 'app/core/core-services/data-send.service';
import { Item } from 'app/shared/models/agenda/item';
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
import { Topic } from 'app/shared/models/topics/topic';
import { ViewTopic } from 'app/site/agenda/models/view-topic';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
import { CreateTopic } from 'app/site/agenda/models/create-topic';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
import { ViewItem } from 'app/site/agenda/models/view-item';
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
/**
* Repository for topics
@ -34,10 +32,10 @@ export class TopicRepositoryService extends BaseAgendaContentObjectRepository<Vi
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Topic, [Mediafile, Item]);
super(DS, dataSend, mapperService, viewModelStoreService, Topic, [Mediafile, Item]);
}
public getAgendaTitle = (topic: Partial<Topic> | Partial<ViewTopic>) => {
@ -69,39 +67,6 @@ export class TopicRepositoryService extends BaseAgendaContentObjectRepository<Vi
return viewTopic;
}
/**
* Save a new topic
*
* @param topicData Partial topic data to be created
* @returns an Identifiable (usually id) as promise
*/
public async create(topic: CreateTopic): Promise<Identifiable> {
return await this.dataSend.createModel(topic);
}
/**
* Change an existing topic
*
* @param updateData form value containing the data meant to update the topic
* @param viewTopic the topic that should receive the update
*/
public async update(updateData: Partial<Topic>, viewTopic: ViewTopic): Promise<void> {
const updateTopic = new Topic();
updateTopic.patchValues(viewTopic.topic);
updateTopic.patchValues(updateData);
return await this.dataSend.updateModel(updateTopic);
}
/**
* Delete a topic
*
* @param viewTopic the topic that should be removed
*/
public async delete(viewTopic: ViewTopic): Promise<void> {
return await this.dataSend.deleteModel(viewTopic.topic);
}
/**
* Returns an array of all duplicates for a topic
*

View File

@ -2,19 +2,19 @@ import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ViewAssignment } from 'app/site/assignments/models/view-assignment';
import { Assignment } from 'app/shared/models/assignments/assignment';
import { User } from 'app/shared/models/users/user';
import { Tag } from 'app/shared/models/core/tag';
import { Item } from 'app/shared/models/agenda/item';
import { DataStoreService } from '../../core-services/data-store.service';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { ViewItem } from 'app/site/agenda/models/view-item';
import { ViewUser } from 'app/site/users/models/view-user';
import { ViewTag } from 'app/site/tags/models/view-tag';
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { DataSendService } from 'app/core/core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service';
import { Item } from 'app/shared/models/agenda/item';
import { Tag } from 'app/shared/models/core/tag';
import { User } from 'app/shared/models/users/user';
import { ViewAssignment } from 'app/site/assignments/models/view-assignment';
import { ViewItem } from 'app/site/agenda/models/view-item';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { ViewTag } from 'app/site/tags/models/view-tag';
import { ViewUser } from 'app/site/users/models/view-user';
/**
* Repository Service for Assignments.
@ -33,11 +33,12 @@ export class AssignmentRepositoryService extends BaseAgendaContentObjectReposito
*/
public constructor(
DS: DataStoreService,
dataSend: DataSendService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Assignment, [User, Item, Tag]);
super(DS, dataSend, mapperService, viewModelStoreService, Assignment, [User, Item, Tag]);
}
public getAgendaTitle = (assignment: Partial<Assignment> | Partial<ViewAssignment>) => {
@ -63,16 +64,4 @@ export class AssignmentRepositoryService extends BaseAgendaContentObjectReposito
viewAssignment.getAgendaTitleWithType = () => this.getAgendaTitleWithType(viewAssignment);
return viewAssignment;
}
public async update(assignment: Partial<Assignment>, viewAssignment: ViewAssignment): Promise<void> {
return null;
}
public async delete(viewAssignment: ViewAssignment): Promise<void> {
return null;
}
public async create(assignment: Assignment): Promise<Identifiable> {
return null;
}
}

View File

@ -1,6 +1,7 @@
import { BaseViewModel } from '../../site/base/base-view-model';
import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
import { CollectionStringMapperService } from '../core-services/collectionStringMapper.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';
@ -21,11 +22,12 @@ export abstract class BaseAgendaContentObjectRepository<
*/
public constructor(
DS: DataStoreService,
dataSend: DataSendService,
collectionStringMapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
baseModelCtor: ModelConstructor<M>,
depsModelCtors?: ModelConstructor<BaseModel>[]
) {
super(DS, collectionStringMapperService, viewModelStoreService, baseModelCtor, depsModelCtors);
super(DS, dataSend, collectionStringMapperService, viewModelStoreService, baseModelCtor, depsModelCtors);
}
}

View File

@ -3,6 +3,7 @@ import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { BaseViewModel } from '../../site/base/base-view-model';
import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
import { CollectionStringMapperService } from '../core-services/collectionStringMapper.service';
import { DataSendService } from '../core-services/data-send.service';
import { DataStoreService } from '../core-services/data-store.service';
import { Identifiable } from '../../shared/models/base/identifiable';
import { auditTime } from 'rxjs/operators';
@ -27,6 +28,8 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
*/
protected readonly viewModelListSubject: BehaviorSubject<V[]> = new BehaviorSubject<V[]>([]);
protected readonly viewModelListAuditSubject: BehaviorSubject<V[]> = new BehaviorSubject<V[]>([]);
/**
* Observable subject for any changes of view models.
*/
@ -59,12 +62,15 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
*/
public constructor(
protected DS: DataStoreService,
protected dataSend: DataSendService,
protected collectionStringMapperService: CollectionStringMapperService,
protected viewModelStoreService: ViewModelStoreService,
protected baseModelCtor: ModelConstructor<M>,
protected depsModelCtors?: ModelConstructor<BaseModel>[]
) {
this._collectionString = baseModelCtor.COLLECTIONSTRING;
this.getViewModelListObservable().subscribe(x => this.viewModelListAuditSubject.next(x));
}
public onAfterAppsLoaded(): void {
@ -137,25 +143,50 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
/**
* Saves the update to an existing model. So called "update"-function
* Provides a default procedure, but can be overwritten if required
*
* @param update the update that should be created
* @param viewModel the view model that the update is based on
*/
public abstract async update(update: Partial<M>, viewModel: V): Promise<void>;
public async update(update: object, viewModel: BaseViewModel): Promise<void> {
const sendUpdate = new this.baseModelCtor();
sendUpdate.patchValues(viewModel.getModel());
sendUpdate.patchValues(update);
return await this.dataSend.partialUpdateModel(sendUpdate);
}
/**
* Deletes a given Model
* @param update the update that should be created
* @param viewModel the view model that the update is based on
* Provides a default procedure, but can be overwritten if required
*
* @param viewModel the view model to delete
*/
public abstract async delete(viewModel: V): Promise<void>;
public async delete(viewModel: BaseViewModel): Promise<void> {
return await this.dataSend.deleteModel(viewModel.getModel());
}
/**
* Creates a new model
* @param update the update that should be created
* @param viewModel the view model that the update is based on
* TODO: remove the viewModel
* Creates a new model.
* Provides a default procedure, but can be overwritten if required
*
* @param model the model to create on the server
*/
public abstract async create(update: M): Promise<Identifiable>;
public async create(model: BaseModel): Promise<Identifiable> {
// this ensures we get a valid base model, even if the view was just
// sending an object with "as MyModelClass"
const sendModel = new this.baseModelCtor();
sendModel.patchValues(model);
// Strips empty fields from the sending mode data.
// required for i.e. users, since group list is mandatory
Object.keys(sendModel).forEach(key => {
if (!sendModel[key]) {
delete sendModel[key];
}
});
return await this.dataSend.createModel(sendModel);
}
/**
* Creates a view model out of a base model.
@ -209,6 +240,16 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
return this.viewModelListSubject.asObservable().pipe(auditTime(1));
}
/**
* Returns the ViewModelList as piped Behavior Subject.
* Prevents unnecessary calls.
*
* @returns A subject that holds the model list
*/
public getViewModelListBehaviorSubject(): BehaviorSubject<V[]> {
return this.viewModelListAuditSubject;
}
/**
* This observable fires every time an object is changed in the repository.
*/

View File

@ -1,12 +1,12 @@
import { Injectable } from '@angular/core';
import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ChatMessage } from 'app/shared/models/core/chat-message';
import { ViewChatMessage } from 'app/site/common/models/view-chatmessage';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { TranslateService } from '@ngx-translate/core';
import { DataSendService } from 'app/core/core-services/data-send.service';
@Injectable({
providedIn: 'root'
@ -14,11 +14,12 @@ import { TranslateService } from '@ngx-translate/core';
export class ChatMessageRepositoryService extends BaseRepository<ViewChatMessage, ChatMessage> {
public constructor(
DS: DataStoreService,
dataSend: DataSendService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, ChatMessage);
super(DS, dataSend, mapperService, viewModelStoreService, ChatMessage);
}
public getVerboseName = (plural: boolean = false) => {
@ -30,16 +31,4 @@ export class ChatMessageRepositoryService extends BaseRepository<ViewChatMessage
viewChatMessage.getVerboseName = this.getVerboseName;
return viewChatMessage;
}
public async create(message: ChatMessage): Promise<Identifiable> {
throw new Error('TODO');
}
public async update(message: Partial<ChatMessage>, viewMessage: ViewChatMessage): Promise<void> {
throw new Error('TODO');
}
public async delete(viewMessage: ViewChatMessage): Promise<void> {
throw new Error('TODO');
}
}

View File

@ -4,10 +4,10 @@ import { Observable, BehaviorSubject } from 'rxjs';
import { BaseRepository } from 'app/core/repositories/base-repository';
import { Config } from 'app/shared/models/core/config';
import { DataSendService } from 'app/core/core-services/data-send.service';
import { DataStoreService } from 'app/core/core-services/data-store.service';
import { ConstantsService } from 'app/core/ui-services/constants.service';
import { HttpService } from 'app/core/core-services/http.service';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { ViewConfig } from 'app/site/config/models/view-config';
@ -97,13 +97,14 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
*/
public constructor(
DS: DataStoreService,
dataSend: DataSendService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private constantsService: ConstantsService,
private http: HttpService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Config);
super(DS, dataSend, mapperService, viewModelStoreService, Config);
this.constantsService.get('OpenSlidesConfigVariables').subscribe(constant => {
this.createConfigStructure(constant);
@ -142,6 +143,7 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
this.updateConfigListObservable();
// Could be raise in error if the root injector is not known
// TODO go over repo
this.DS.changeObservable.subscribe(model => {
if (model instanceof Config) {
this.viewModelStore[model.id] = this.createViewModel(model as Config);
@ -219,26 +221,6 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
await this.http.put('rest/' + updatedConfig.collectionString + '/' + updatedConfig.key + '/', updatedConfig);
}
/**
* This particular function should never be necessary since the creation of config
* values is not planed.
*
* Function exists solely to correctly implement {@link BaseRepository}
*/
public async delete(config: ViewConfig): Promise<void> {
throw new Error('Config variables cannot be deleted');
}
/**
* This particular function should never be necessary since the creation of config
* values is not planed.
*
* Function exists solely to correctly implement {@link BaseRepository}
*/
public async create(config: Config): Promise<Identifiable> {
throw new Error('Config variables cannot be created');
}
/**
* initially create the config structure from the given constant.
* @param constant

View File

@ -5,13 +5,13 @@ import { DataStoreService } from 'app/core/core-services/data-store.service';
import { BaseRepository } from 'app/core/repositories/base-repository';
import { History } from 'app/shared/models/core/history';
import { User } from 'app/shared/models/users/user';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { HttpService } from 'app/core/core-services/http.service';
import { ViewHistory } from 'app/site/history/models/view-history';
import { TimeTravelService } from 'app/core/core-services/time-travel.service';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { ViewUser } from 'app/site/users/models/view-user';
import { TranslateService } from '@ngx-translate/core';
import { DataSendService } from 'app/core/core-services/data-send.service';
/**
* Repository for the history.
@ -32,13 +32,14 @@ export class HistoryRepositoryService extends BaseRepository<ViewHistory, Histor
*/
public constructor(
DS: DataStoreService,
dataSend: DataSendService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private httpService: HttpService,
private timeTravel: TimeTravelService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, History, [User]);
super(DS, dataSend, mapperService, viewModelStoreService, History, [User]);
}
public getVerboseName = (plural: boolean = false) => {
@ -58,22 +59,6 @@ export class HistoryRepositoryService extends BaseRepository<ViewHistory, Histor
return viewHistory;
}
/**
* Clients usually do not need to create a history object themselves
* @ignore
*/
public async create(): Promise<Identifiable> {
throw new Error('You cannot create a history object');
}
/**
* Clients usually do not need to modify existing history objects
* @ignore
*/
public async update(): Promise<void> {
throw new Error('You cannot update a history object');
}
/**
* Sends a post-request to delete history objects
*/

View File

@ -32,11 +32,11 @@ export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Me
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private httpService: HttpService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Mediafile, [User]);
super(DS, dataSend, mapperService, viewModelStoreService, Mediafile, [User]);
}
public getVerboseName = (plural: boolean = false) => {
@ -56,39 +56,6 @@ export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Me
return viewMediafile;
}
/**
* Alter a given mediaFile
* Usually just i.e change the name and the hidden flag.
*
* @param file contains the new values
* @param viewFile the file that should be updated
*/
public async update(file: Partial<Mediafile>, viewFile: ViewMediafile): Promise<void> {
const updateFile = new Mediafile();
updateFile.patchValues(viewFile.mediafile);
updateFile.patchValues(file);
await this.dataSend.updateModel(updateFile);
}
/**
* Deletes the given file from the server
*
* @param file the file to delete
*/
public async delete(file: ViewMediafile): Promise<void> {
return await this.dataSend.deleteModel(file.mediafile);
}
/**
* Mediafiles are uploaded using FormData objects and (usually) not created locally.
*
* @param file a new mediafile
* @returns the ID as a promise
*/
public async create(file: Mediafile): Promise<Identifiable> {
return await this.dataSend.createModel(file);
}
/**
* Uploads a file to the server.
* The HttpHeader should be Application/FormData, the empty header will

View File

@ -10,7 +10,6 @@ import { ConfigService } from 'app/core/ui-services/config.service';
import { DataSendService } from '../../core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service';
import { HttpService } from '../../core-services/http.service';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { ViewCategory } from 'app/site/motions/models/view-category';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
@ -44,12 +43,12 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
protected DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private httpService: HttpService,
private configService: ConfigService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Category);
super(DS, dataSend, mapperService, viewModelStoreService, Category);
}
public getVerboseName = (plural: boolean = false) => {
@ -62,26 +61,6 @@ export class CategoryRepositoryService extends BaseRepository<ViewCategory, Cate
return viewCategory;
}
public async create(newCategory: Category): Promise<Identifiable> {
return await this.dataSend.createModel(newCategory);
}
public async update(category: Partial<Category>, viewCategory: ViewCategory): Promise<void> {
let updateCategory: Category;
if (viewCategory) {
updateCategory = viewCategory.category;
} else {
updateCategory = new Category();
}
updateCategory.patchValues(category);
await this.dataSend.updateModel(updateCategory);
}
public async delete(viewCategory: ViewCategory): Promise<void> {
const category = viewCategory.category;
await this.dataSend.deleteModel(category);
}
/**
* Returns the category for the ID
* @param category_id category ID

View File

@ -47,10 +47,14 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, MotionChangeRecommendation, [Category, User, Workflow]);
super(DS, dataSend, mapperService, viewModelStoreService, MotionChangeRecommendation, [
Category,
User,
Workflow
]);
}
public getVerboseName = (plural: boolean = false) => {
@ -68,16 +72,6 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<
return viewMotionChangeRecommendation;
}
/**
* Creates a change recommendation
* Creates a (real) change recommendation and delegates it to the {@link DataSendService}
*
* @param {MotionChangeRecommendation} changeReco
*/
public async create(changeReco: MotionChangeRecommendation): Promise<Identifiable> {
return await this.dataSend.createModel(changeReco);
}
/**
* Given a change recommendation view object, a entry in the backend is created.
* @param view
@ -87,35 +81,6 @@ export class ChangeRecommendationRepositoryService extends BaseRepository<
return await this.dataSend.createModel(view.changeRecommendation);
}
/**
* Deleting a change recommendation.
*
* Extract the change recommendation out of the viewModel and delegate
* to {@link DataSendService}
* @param {ViewMotionChangeRecommendation} viewModel
*/
public async delete(viewModel: ViewMotionChangeRecommendation): Promise<void> {
await this.dataSend.deleteModel(viewModel.changeRecommendation);
}
/**
* updates a change recommendation
*
* Updates a (real) change recommendation with patched data and delegate it
* to the {@link DataSendService}
*
* @param {Partial<MotionChangeRecommendation>} update the form data containing the update values
* @param {ViewMotionChangeRecommendation} viewModel The View Change Recommendation. If not present, a new motion will be created
*/
public async update(
update: Partial<MotionChangeRecommendation>,
viewModel: ViewMotionChangeRecommendation
): Promise<void> {
const changeReco = viewModel.changeRecommendation;
changeReco.patchValues(update);
await this.dataSend.partialUpdateModel(changeReco);
}
/**
* return the Observable of all change recommendations belonging to the given motion
*/

View File

@ -8,7 +8,6 @@ import { CollectionStringMapperService } from 'app/core/core-services/collection
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 { Identifiable } from 'app/shared/models/base/identifiable';
import { Motion } from 'app/shared/models/motions/motion';
import { MotionBlock } from 'app/shared/models/motions/motion-block';
import { MotionRepositoryService } from './motion-repository.service';
@ -39,12 +38,12 @@ export class MotionBlockRepositoryService extends BaseAgendaContentObjectReposit
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private motionRepo: MotionRepositoryService,
private httpService: HttpService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, MotionBlock, [Item]);
super(DS, dataSend, mapperService, viewModelStoreService, MotionBlock, [Item]);
}
public getAgendaTitle = (motionBlock: Partial<MotionBlock> | Partial<ViewMotionBlock>) => {
@ -74,38 +73,6 @@ export class MotionBlockRepositoryService extends BaseAgendaContentObjectReposit
return viewMotionBlock;
}
/**
* Updates a given motion block
*
* @param update a partial motion block containing the update data
* @param viewBlock the motion block to update
*/
public async update(update: Partial<MotionBlock>, viewBlock: ViewMotionBlock): Promise<void> {
const updateMotionBlock = new MotionBlock();
updateMotionBlock.patchValues(viewBlock.motionBlock);
updateMotionBlock.patchValues(update);
return await this.dataSend.updateModel(updateMotionBlock);
}
/**
* Deletes a motion block from the server
*
* @param newBlock the motion block to delete
*/
public async delete(newBlock: ViewMotionBlock): Promise<void> {
return await this.dataSend.deleteModel(newBlock.motionBlock);
}
/**
* Creates a new motion block to the server
*
* @param newBlock The new block to create
* @returns the ID of the created model as promise
*/
public async create(newBlock: MotionBlock): Promise<Identifiable> {
return await this.dataSend.createModel(newBlock);
}
/**
* Removes the motion block id from the given motion
*

View File

@ -6,7 +6,6 @@ import { BaseRepository } from '../base-repository';
import { ViewMotionCommentSection } from 'app/site/motions/models/view-motion-comment-section';
import { MotionCommentSection } from 'app/shared/models/motions/motion-comment-section';
import { Group } from 'app/shared/models/users/group';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { HttpService } from 'app/core/core-services/http.service';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
@ -45,11 +44,11 @@ export class MotionCommentSectionRepositoryService extends BaseRepository<
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private http: HttpService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, MotionCommentSection, [Group]);
super(DS, dataSend, mapperService, viewModelStoreService, MotionCommentSection, [Group]);
}
public getVerboseName = (plural: boolean = false) => {
@ -70,42 +69,6 @@ export class MotionCommentSectionRepositoryService extends BaseRepository<
return viewMotionCommentSection;
}
/**
* Creates the Comment Section
*
* @param section section to be created
* @returns the promise to create the comment section
*/
public async create(section: MotionCommentSection): Promise<Identifiable> {
return await this.dataSend.createModel(section);
}
/**
* Updates an existion CommentSection
*
* @param section the update that the section should be created on
* @param viewSection the view model representation of that section
*/
public async update(section: Partial<MotionCommentSection>, viewSection?: ViewMotionCommentSection): Promise<void> {
let updateSection: MotionCommentSection;
if (viewSection) {
updateSection = viewSection.section;
} else {
updateSection = new MotionCommentSection();
}
updateSection.patchValues(section);
await this.dataSend.updateModel(updateSection);
}
/**
* Deletes a MotionCommentSection
*
* @param viewSection the view model representation of the model that should be deleted
*/
public async delete(viewSection: ViewMotionCommentSection): Promise<void> {
await this.dataSend.deleteModel(viewSection.section);
}
/**
* Saves a comment made at a MotionCommentSection. Does an update, if
* there is a comment text. Deletes the comment, if the text is empty.

View File

@ -7,12 +7,10 @@ import { tap, map } from 'rxjs/operators';
import { Category } from 'app/shared/models/motions/category';
import { ChangeRecoMode, ViewMotion } from 'app/site/motions/models/view-motion';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { CreateMotion } from 'app/site/motions/models/create-motion';
import { DataSendService } from '../../core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service';
import { DiffLinesInParagraph, DiffService, LineRange, ModificationType } from '../../ui-services/diff.service';
import { HttpService } from 'app/core/core-services/http.service';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { Item } from 'app/shared/models/agenda/item';
import { LinenumberingService } from '../../ui-services/linenumbering.service';
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
@ -75,7 +73,7 @@ export class MotionRepositoryService extends BaseAgendaContentObjectRepository<V
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private httpService: HttpService,
private readonly lineNumbering: LinenumberingService,
private readonly diff: DiffService,
@ -83,7 +81,7 @@ export class MotionRepositoryService extends BaseAgendaContentObjectRepository<V
private translate: TranslateService,
private operator: OperatorService
) {
super(DS, mapperService, viewModelStoreService, Motion, [
super(DS, dataSend, mapperService, viewModelStoreService, Motion, [
Category,
User,
Workflow,
@ -258,45 +256,6 @@ export class MotionRepositoryService extends BaseAgendaContentObjectRepository<V
);
}
/**
* Creates a motion
* Creates a (real) motion with patched data and delegate it
* to the {@link DataSendService}
*
* @param update the form data containing the updated values
* @param viewMotion The View Motion. If not present, a new motion will be created
*/
public async create(motion: CreateMotion): Promise<Identifiable> {
// TODO how to handle category id and motion_block id in CreateMotion?
return await this.dataSend.createModel(motion);
}
/**
* updates a motion
*
* Creates a (real) motion with patched data and delegate it
* to the {@link DataSendService}
*
* @param update the form data containing the updated values
* @param viewMotion The View Motion. If not present, a new motion will be created
*/
public async update(update: Partial<Motion>, viewMotion: ViewMotion): Promise<void> {
const motion = viewMotion.motion;
motion.patchValues(update);
return await this.dataSend.partialUpdateModel(motion);
}
/**
* Deleting a motion.
*
* Extract the motion out of the motionView and delegate
* to {@link DataSendService}
* @param viewMotion
*/
public async delete(viewMotion: ViewMotion): Promise<void> {
return await this.dataSend.deleteModel(viewMotion.motion);
}
/**
* Set the state of a motion
*

View File

@ -5,7 +5,6 @@ import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { ViewStatuteParagraph } from 'app/site/motions/models/view-statute-paragraph';
import { StatuteParagraph } from 'app/shared/models/motions/statute-paragraph';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { TranslateService } from '@ngx-translate/core';
@ -34,10 +33,10 @@ export class StatuteParagraphRepositoryService extends BaseRepository<ViewStatut
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, StatuteParagraph);
super(DS, dataSend, mapperService, viewModelStoreService, StatuteParagraph);
}
public getVerboseName = (plural: boolean = false) => {
@ -49,21 +48,4 @@ export class StatuteParagraphRepositoryService extends BaseRepository<ViewStatut
viewStatuteParagraph.getVerboseName = this.getVerboseName;
return viewStatuteParagraph;
}
public async create(statuteParagraph: StatuteParagraph): Promise<Identifiable> {
return await this.dataSend.createModel(statuteParagraph);
}
public async update(
statuteParagraph: Partial<StatuteParagraph>,
viewStatuteParagraph: ViewStatuteParagraph
): Promise<void> {
const updateParagraph = viewStatuteParagraph.statuteParagraph;
updateParagraph.patchValues(statuteParagraph);
await this.dataSend.updateModel(updateParagraph);
}
public async delete(viewStatuteParagraph: ViewStatuteParagraph): Promise<void> {
await this.dataSend.deleteModel(viewStatuteParagraph.statuteParagraph);
}
}

View File

@ -6,7 +6,6 @@ import { ViewWorkflow } from 'app/site/motions/models/view-workflow';
import { DataSendService } from '../../core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { WorkflowState } from 'app/shared/models/motions/workflow-state';
import { ViewMotion } from 'app/site/motions/models/view-motion';
@ -45,12 +44,12 @@ export class WorkflowRepositoryService extends BaseRepository<ViewWorkflow, Work
public constructor(
DS: DataStoreService,
mapperService: CollectionStringMapperService,
private httpService: HttpService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private httpService: HttpService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Workflow);
super(DS, dataSend, mapperService, viewModelStoreService, Workflow);
this.viewModelListSubject.pipe(auditTime(1)).subscribe(models => {
if (models && models.length > 0) {
this.initSorting(models);
@ -87,43 +86,6 @@ export class WorkflowRepositoryService extends BaseRepository<ViewWorkflow, Work
return viewWorkflow;
}
/**
* Creates a new workflow
*
* @param newWorkflow the workflow to create
* @returns the ID of a new workflow as promise
*/
public async create(newWorkflow: Workflow): Promise<Identifiable> {
return await this.dataSend.createModel(newWorkflow);
}
/**
* Updates the workflow by the given changes
*
* @param workflow Contains the update
* @param viewWorkflow the target workflow
*/
public async update(workflow: Partial<Workflow>, viewWorkflow: ViewWorkflow): Promise<void> {
let updateWorkflow: Workflow;
if (viewWorkflow) {
updateWorkflow = viewWorkflow.workflow;
} else {
updateWorkflow = new Workflow();
}
updateWorkflow.patchValues(workflow);
await this.dataSend.updateModel(updateWorkflow);
}
/**
* Deletes the given workflow
*
* @param viewWorkflow the workflow to delete
*/
public async delete(viewWorkflow: ViewWorkflow): Promise<void> {
const workflow = viewWorkflow.workflow;
await this.dataSend.deleteModel(workflow);
}
/**
* Adds a new state to the given workflow
*

View File

@ -2,7 +2,6 @@ import { Injectable } from '@angular/core';
import { DataSendService } from '../../core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ViewCountdown } from 'app/site/projector/models/view-countdown';
import { Countdown } from 'app/shared/models/core/countdown';
@ -18,11 +17,11 @@ export class CountdownRepositoryService extends BaseRepository<ViewCountdown, Co
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private translate: TranslateService,
private servertimeService: ServertimeService
) {
super(DS, mapperService, viewModelStoreService, Countdown);
super(DS, dataSend, mapperService, viewModelStoreService, Countdown);
}
public getVerboseName = (plural: boolean = false) => {
@ -35,20 +34,6 @@ export class CountdownRepositoryService extends BaseRepository<ViewCountdown, Co
return viewCountdown;
}
public async create(countdown: Countdown): Promise<Identifiable> {
return await this.dataSend.createModel(countdown);
}
public async update(countdown: Partial<Countdown>, viewCountdown: ViewCountdown): Promise<void> {
const update = viewCountdown.countdown;
update.patchValues(countdown);
await this.dataSend.updateModel(update);
}
public async delete(countdown: ViewCountdown): Promise<void> {
await this.dataSend.deleteModel(countdown.countdown);
}
public async start(countdown: ViewCountdown): Promise<void> {
const endTime = this.servertimeService.getServertime() / 1000 + countdown.countdown_time;
await this.update({ running: true, countdown_time: endTime }, countdown);

View File

@ -1,7 +1,6 @@
import { Injectable } from '@angular/core';
import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
import { ViewProjectorMessage } from 'app/site/projector/models/view-projector-message';
@ -17,10 +16,10 @@ export class ProjectorMessageRepositoryService extends BaseRepository<ViewProjec
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private translate: TranslateService,
private dataSend: DataSendService
protected dataSend: DataSendService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, ProjectorMessage);
super(DS, dataSend, mapperService, viewModelStoreService, ProjectorMessage);
}
public getVerboseName = (plural: boolean = false) => {
@ -32,18 +31,4 @@ export class ProjectorMessageRepositoryService extends BaseRepository<ViewProjec
viewProjectorMessage.getVerboseName = this.getVerboseName;
return viewProjectorMessage;
}
public async create(message: ProjectorMessage): Promise<Identifiable> {
return await this.dataSend.createModel(message);
}
public async update(message: Partial<ProjectorMessage>, viewMessage: ViewProjectorMessage): Promise<void> {
const update = viewMessage.projectormessage;
update.patchValues(message);
await this.dataSend.updateModel(update);
}
public async delete(viewMessage: ViewProjectorMessage): Promise<void> {
await this.dataSend.deleteModel(viewMessage.projectormessage);
}
}

View File

@ -39,11 +39,11 @@ export class ProjectorRepositoryService extends BaseRepository<ViewProjector, Pr
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private http: HttpService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Projector, [Projector]);
super(DS, dataSend, mapperService, viewModelStoreService, Projector, [Projector]);
}
public getVerboseName = (plural: boolean = false) => {
@ -66,25 +66,6 @@ export class ProjectorRepositoryService extends BaseRepository<ViewProjector, Pr
return await this.dataSend.createModel(projector);
}
/**
* Updates a projector.
*/
public async update(projectorData: Partial<Projector>, viewProjector: ViewProjector): Promise<void> {
const projector = new Projector();
projector.patchValues(viewProjector.projector);
projector.patchValues(projectorData);
await this.dataSend.updateModel(projector);
}
/**
* Deletes a given projector.
*
* @param projector
*/
public async delete(projector: ViewProjector): Promise<void> {
await this.dataSend.deleteModel(projector.projector);
}
/**
* Scroll the given projector.
*

View File

@ -5,7 +5,6 @@ import { ViewTag } from 'app/site/tags/models/view-tag';
import { DataSendService } from '../../core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { TranslateService } from '@ngx-translate/core';
@ -34,13 +33,13 @@ export class TagRepositoryService extends BaseRepository<ViewTag, Tag> {
* @param dataSend sending changed objects
*/
public constructor(
protected DS: DataStoreService,
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Tag);
super(DS, dataSend, mapperService, viewModelStoreService, Tag);
}
public getVerboseName = (plural: boolean = false) => {
@ -52,21 +51,4 @@ export class TagRepositoryService extends BaseRepository<ViewTag, Tag> {
viewTag.getVerboseName = this.getVerboseName;
return viewTag;
}
public async create(update: Tag): Promise<Identifiable> {
const newTag = new Tag();
newTag.patchValues(update);
return await this.dataSend.createModel(newTag);
}
public async update(update: Partial<Tag>, viewTag: ViewTag): Promise<void> {
const updateTag = new Tag();
updateTag.patchValues(viewTag.tag);
updateTag.patchValues(update);
await this.dataSend.updateModel(updateTag);
}
public async delete(viewTag: ViewTag): Promise<void> {
await this.dataSend.deleteModel(viewTag.tag);
}
}

View File

@ -6,7 +6,6 @@ import { ConstantsService } from '../../ui-services/constants.service';
import { DataSendService } from '../../core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service';
import { Group } from 'app/shared/models/users/group';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { ViewGroup } from 'app/site/users/models/view-group';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { TranslateService } from '@ngx-translate/core';
@ -52,11 +51,11 @@ export class GroupRepositoryService extends BaseRepository<ViewGroup, Group> {
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private constants: ConstantsService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, Group);
super(DS, dataSend, mapperService, viewModelStoreService, Group);
this.sortPermsPerApp();
}
@ -161,35 +160,4 @@ export class GroupRepositoryService extends BaseRepository<ViewGroup, Group> {
}
});
}
/**
* creates and saves a new user
*
* @param groupData form value. Usually not yet a real user
*/
public async create(groupData: Partial<Group>): Promise<Identifiable> {
const newGroup = new Group();
newGroup.patchValues(groupData);
return await this.dataSend.createModel(newGroup);
}
/**
* Updates the given Group with the new permission
*
* @param permission the new permission
* @param viewGroup the selected Group
*/
public async update(groupData: Partial<Group>, viewGroup: ViewGroup): Promise<void> {
const updateGroup = new Group();
updateGroup.patchValues(viewGroup.group);
updateGroup.patchValues(groupData);
await this.dataSend.updateModel(updateGroup);
}
/**
* Deletes a given group
*/
public async delete(viewGroup: ViewGroup): Promise<void> {
await this.dataSend.deleteModel(viewGroup.group);
}
}

View File

@ -4,10 +4,10 @@ import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { PersonalNote } from 'app/shared/models/users/personal-note';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { ViewPersonalNote } from 'app/site/users/models/view-personal-note';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { TranslateService } from '@ngx-translate/core';
import { DataSendService } from 'app/core/core-services/data-send.service';
/**
*/
@ -21,11 +21,12 @@ export class PersonalNoteRepositoryService extends BaseRepository<ViewPersonalNo
*/
public constructor(
DS: DataStoreService,
dataSend: DataSendService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private translate: TranslateService
) {
super(DS, mapperService, viewModelStoreService, PersonalNote);
super(DS, dataSend, mapperService, viewModelStoreService, PersonalNote);
}
public getVerboseName = (plural: boolean = false) => {
@ -37,16 +38,4 @@ export class PersonalNoteRepositoryService extends BaseRepository<ViewPersonalNo
viewPersonalNote.getVerboseName = this.getVerboseName;
return viewPersonalNote;
}
public async create(personalNote: PersonalNote): Promise<Identifiable> {
throw new Error('Not supported');
}
public async update(personalNote: Partial<PersonalNote>, viewPersonalNote: ViewPersonalNote): Promise<void> {
throw new Error('Not supported');
}
public async delete(viewPersonalNote: ViewPersonalNote): Promise<void> {
throw new Error('Not supported');
}
}

View File

@ -10,7 +10,6 @@ import { DataStoreService } from '../../core-services/data-store.service';
import { environment } from '../../../../environments/environment';
import { Group } from 'app/shared/models/users/group';
import { HttpService } from 'app/core/core-services/http.service';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { NewEntry } from 'app/core/ui-services/base-import.service';
import { User } from 'app/shared/models/users/user';
import { ViewUser } from 'app/site/users/models/view-user';
@ -43,12 +42,12 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
DS: DataStoreService,
mapperService: CollectionStringMapperService,
viewModelStoreService: ViewModelStoreService,
private dataSend: DataSendService,
protected dataSend: DataSendService,
private translate: TranslateService,
private httpService: HttpService,
private configService: ConfigService
) {
super(DS, mapperService, viewModelStoreService, User, [Group]);
super(DS, dataSend, mapperService, viewModelStoreService, User, [Group]);
}
public getVerboseName = (plural: boolean = false) => {
@ -67,13 +66,14 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
/**
* Updates a the selected user with the form values.
* Since user should actually "delete" field, the unified update method
* cannot be used
*
* @param update the forms values
* @param viewUser
*/
public async update(update: Partial<User>, viewUser: ViewUser): Promise<void> {
const updateUser = new User();
// copy the ViewUser to avoid manipulation of parameters
updateUser.patchValues(viewUser.user);
updateUser.patchValues(update);
@ -89,37 +89,7 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
updateUser.gender = '';
}
return await this.dataSend.updateModel(updateUser);
}
/**
* Deletes a given user
*/
public async delete(viewUser: ViewUser): Promise<void> {
return await this.dataSend.deleteModel(viewUser.user);
}
/**
* creates and saves a new user
*
* TODO: used over not-yet-existing detail view
* @param userData blank form value. Usually not yet a real user
*/
public async create(userData: Partial<User>): Promise<Identifiable> {
const newUser = new User();
// collectionString of userData is still empty
newUser.patchValues(userData);
// during creation, the server demands that basically nothing must be null.
// during the update process, null values are interpreted as delete.
// therefore, remove "null" values.
Object.keys(newUser).forEach(key => {
if (!newUser[key]) {
delete newUser[key];
}
});
return await this.dataSend.createModel(newUser);
return await this.dataSend.partialUpdateModel(updateUser);
}
/**

View File

@ -6,6 +6,9 @@
.sticky-toolbar {
position: -webkit-sticky;
position: -moz-sticky;
position: -ms-sticky;
position: -o-sticky;
position: sticky;
top: 0px;
z-index: 3;

View File

@ -87,7 +87,7 @@ export class SearchValueSelectorComponent implements OnInit, OnDestroy {
this._inputListSubscription.unsubscribe();
}
this._inputListSubject = value;
this._inputListSubscription = this._inputListSubject.subscribe(values => {
this._inputListSubscription = this._inputListSubject.subscribe(() => {
this.filterItems();
});
}

View File

@ -159,9 +159,8 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
*/
public ngOnInit(): void {
// load and observe users
this.users = new BehaviorSubject(this.userRepository.getViewModelList());
this.userRepository.getSortedViewModelListObservable().subscribe(users => {
this.users.next(users);
this.users = this.userRepository.getViewModelListBehaviorSubject();
this.userRepository.getViewModelListBehaviorSubject().subscribe(newUsers => {
if (this.viewItem) {
this.setSpeakerList(this.viewItem.id);
}

View File

@ -96,13 +96,8 @@ export class TopicDetailComponent extends BaseViewComponent {
this.getTopicByUrl();
this.createForm();
this.mediafilesObserver = new BehaviorSubject(this.mediafileRepo.getViewModelList());
this.itemObserver = new BehaviorSubject(this.itemRepo.getViewModelList());
this.mediafileRepo
.getViewModelListObservable()
.subscribe(mediafiles => this.mediafilesObserver.next(mediafiles));
this.itemRepo.getViewModelListObservable().subscribe(items => this.itemObserver.next(items));
this.mediafilesObserver = this.mediafileRepo.getViewModelListBehaviorSubject();
this.itemObserver = this.itemRepo.getViewModelListBehaviorSubject();
}
/**

View File

@ -1,5 +1,6 @@
import { CreateTopic } from './create-topic';
import { ViewTopic } from './view-topic';
import { Topic } from 'app/shared/models/topics/topic';
/**
* View model for Topic('Agenda item') creation.
@ -108,6 +109,10 @@ export class ViewCreateTopic extends ViewTopic {
super(topic);
}
public getModel(): Topic {
return super.getModel();
}
public getVerboseName = () => {
throw new Error('This should not be used');
};

View File

@ -132,6 +132,10 @@ export class ViewItem extends BaseViewModel {
this._contentObject = contentObject;
}
public getModel(): Item {
return this.item;
}
public updateDependencies(update: BaseViewModel): boolean {
if (
update &&

View File

@ -1,6 +1,7 @@
import { BaseViewModel } from 'app/site/base/base-view-model';
import { Speaker, SpeakerState } from 'app/shared/models/agenda/speaker';
import { ViewUser } from 'app/site/users/models/view-user';
import { User } from 'app/shared/models/users/user';
/**
* Provides "safe" access to a speaker with all it's components
@ -70,6 +71,10 @@ export class ViewSpeaker extends BaseViewModel {
return this.name;
};
public getModel(): User {
return this.user.user;
}
/**
* Speaker is not a base model,
* @param update the incoming update

View File

@ -71,6 +71,10 @@ export class ViewTopic extends BaseAgendaViewModel {
}
};
public getModel(): Topic {
return this.topic;
}
public getAgendaItem(): ViewItem {
return this.agendaItem;
}

View File

@ -75,6 +75,10 @@ export class ViewAssignment extends BaseAgendaViewModel {
return this.title;
};
public getModel(): Assignment {
return this.assignment;
}
public formatForSearch(): SearchRepresentation {
return [this.title];
}

View File

@ -1,6 +1,7 @@
import { Displayable } from './displayable';
import { Identifiable } from '../../shared/models/base/identifiable';
import { Collection } from 'app/shared/models/base/collection';
import { BaseModel } from 'app/shared/models/base/base-model';
export interface ViewModelConstructor<T extends BaseViewModel> {
COLLECTIONSTRING: string;
@ -56,6 +57,9 @@ export abstract class BaseViewModel implements Displayable, Identifiable, Collec
return this.getTitle();
};
/** return the main model of a view model */
public abstract getModel(): BaseModel;
public abstract updateDependencies(update: BaseViewModel): void;
public toString(): string {

View File

@ -34,6 +34,18 @@ export abstract class BaseViewComponent extends BaseComponent implements OnDestr
this.subscriptions = [];
}
/**
* automatically dismisses the error snack bar and clears subscriptions
* if the component is destroyed.
*/
public ngOnDestroy(): void {
if (this.messageSnackBar) {
this.messageSnackBar.dismiss();
}
this.cleanSubjects();
}
/**
* Opens the snack bar with the given message.
* This snack bar will only dismiss if the user clicks the 'OK'-button.
@ -65,24 +77,23 @@ export abstract class BaseViewComponent extends BaseComponent implements OnDestr
}
/**
* To catch swipe gestures.
* Should be overwritten by children which need swipe gestures
* Manually clears all stored subscriptions.
* Necessary for manual routing control, since the Angular
* life cycle does not accept that navigation to the same URL
* executes the life cycle again
*/
protected swipe(e: TouchEvent, when: string): void {}
/**
* automatically dismisses the error snack bar and clears subscriptions
* if the component is destroyed.
*/
public ngOnDestroy(): void {
if (this.messageSnackBar) {
this.messageSnackBar.dismiss();
}
protected cleanSubjects(): void {
if (this.subscriptions.length > 0) {
for (const sub of this.subscriptions) {
sub.unsubscribe();
}
this.subscriptions = [];
}
}
/**
* To catch swipe gestures.
* Should be overwritten by children which need swipe gestures
*/
protected swipe(e: TouchEvent, when: string): void {}
}

View File

@ -104,7 +104,7 @@ export abstract class ListViewBaseComponent<V extends BaseViewModel, M extends B
}
/**
* Standard sorting function. Siffucient for most list views but can be overwritten
* Standard sorting function. Sufficient for most list views but can be overwritten
*/
protected onSort(): void {
this.subscriptions.push(

View File

@ -4,11 +4,11 @@ import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; // showcase
import { BaseComponent } from 'app/base.component';
import { ConfigService } from 'app/core/ui-services/config.service';
// for testing the DS and BaseModel
import { Config } from 'app/shared/models/core/config';
import { DataStoreService } from 'app/core/core-services/data-store.service';
/**
* The start component. Greeting page for OpenSlides
*/
@Component({
selector: 'os-start',
templateUrl: './start.component.html'
@ -22,8 +22,9 @@ export class StartComponent extends BaseComponent implements OnInit {
*
* @param titleService the title serve
* @param translate to translation module
* @param configService read out config values
*/
public constructor(titleService: Title, protected translate: TranslateService, private DS: DataStoreService) {
public constructor(titleService: Title, translate: TranslateService, private configService: ConfigService) {
super(titleService, translate);
}
@ -31,51 +32,18 @@ export class StartComponent extends BaseComponent implements OnInit {
* Init the component.
*
* Sets the welcomeTitle and welcomeText.
* Tries to read them from the DataStore (which will fail initially)
* And observes DataStore for changes
* Set title and observe DataStore for changes.
*/
public ngOnInit(): void {
// required dummy translation, cause translations for config values were never set
// tslint:disable-next-line
const welcomeTitleTranslateDummy = this.translate.instant('Welcome to OpenSlides');
super.setTitle('Home');
// set welcome title and text
const welcomeTitleConfig = this.DS.filter<Config>(
Config,
config => config.key === 'general_event_welcome_title'
)[0] as Config;
if (welcomeTitleConfig) {
this.welcomeTitle = welcomeTitleConfig.value as string;
}
// set the welcome title
this.configService
.get<string>('general_event_welcome_title')
.subscribe(welcomeTitle => (this.welcomeTitle = welcomeTitle));
const welcomeTextConfig = this.DS.filter<Config>(
Config,
config => config.key === 'general_event_welcome_text'
)[0] as Config;
if (welcomeTextConfig) {
this.welcomeText = welcomeTextConfig.value as string;
}
// observe title and text in DS
this.DS.changeObservable.subscribe(newModel => {
if (newModel instanceof Config) {
if (newModel.key === 'general_event_welcome_title') {
this.welcomeTitle = newModel.value as string;
} else if (newModel.key === 'general_event_welcome_text') {
this.welcomeText = newModel.value as string;
}
}
});
}
/**
* test translations in component
*/
public TranslateTest(): void {
console.log('lets translate the word "motion" in the current in the current lang');
console.log('Motions in ' + this.translate.currentLang + ' is ' + this.translate.instant('Motions'));
// set the welcome text
this.configService
.get<string>('general_event_welcome_text')
.subscribe(welcomeText => (this.welcomeText = welcomeText as string));
}
}

View File

@ -32,5 +32,9 @@ export class ViewChatMessage extends BaseViewModel {
return 'Chatmessage';
};
public getModel(): ChatMessage {
return this.chatmessage;
}
public updateDependencies(message: BaseViewModel): void {}
}

View File

@ -111,6 +111,10 @@ export class ViewConfig extends BaseViewModel {
public updateDependencies(update: BaseViewModel): void {}
public getModel(): Config {
return this.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,

View File

@ -113,6 +113,10 @@ export class ViewHistory extends BaseViewModel {
return this.element_id;
};
public getModel(): History {
return this.history;
}
/**
* Updates the history object with new values
*

View File

@ -80,6 +80,10 @@ export class ViewMediafile extends BaseProjectableViewModel implements Searchabl
return this.title;
};
public getModel(): Mediafile {
return this.mediafile;
}
public formatForSearch(): SearchRepresentation {
const searchValues = [this.title];
if (this.uploader) {

View File

@ -65,6 +65,10 @@ export class ViewCategory extends BaseViewModel implements Searchable {
return '/motions/category';
}
public getModel(): Category {
return this.category;
}
/**
* Updates the local objects if required
* @param update

View File

@ -39,6 +39,10 @@ export class ViewMotionChangeRecommendation extends BaseViewModel implements Vie
public updateDependencies(update: BaseViewModel): void {}
public getModel(): MotionChangeRecommendation {
return this.changeRecommendation;
}
public updateChangeReco(type: number, text: string, internal: boolean): void {
// @TODO HTML sanitazion
this._changeRecommendation.type = type;

View File

@ -81,6 +81,10 @@ export class ViewMotionBlock extends BaseAgendaViewModel implements Searchable {
return this.title;
};
public getModel(): MotionBlock {
return this.motionBlock;
}
public getSlide(): ProjectorElementBuildDeskriptor {
return {
getBasicProjectorElement: options => ({

View File

@ -65,6 +65,10 @@ export class ViewMotionCommentSection extends BaseViewModel {
return this.name;
};
public getModel(): MotionCommentSection {
return this.section;
}
/**
* Updates the local objects if required
* @param section

View File

@ -396,6 +396,10 @@ export class ViewMotion extends BaseAgendaViewModel implements Searchable {
return this.item;
}
public getModel(): Motion {
return this.motion;
}
/**
* Formats the category for search
*

View File

@ -49,6 +49,10 @@ export class ViewStatuteParagraph extends BaseViewModel implements Searchable {
return this.title;
};
public getModel(): StatuteParagraph {
return this.statuteParagraph;
}
public formatForSearch(): SearchRepresentation {
return [this.title];
}

View File

@ -61,6 +61,10 @@ export class ViewWorkflow extends BaseViewModel {
this.workflow.sortStates();
}
public getModel(): Workflow {
return this.workflow;
}
/**
* Updates the local objects if required
*

View File

@ -105,9 +105,9 @@ export class MotionBlockListComponent extends ListViewBaseComponent<ViewMotionBl
super.setTitle('Motion Blocks');
this.initTable();
this.items = new BehaviorSubject(this.itemRepo.getViewModelList());
this.itemRepo.getViewModelListObservable().subscribe(items => this.items.next(items));
this.items = this.itemRepo.getViewModelListBehaviorSubject();
// TODO: Should fall under generic sorting in PR 4411
this.repo.getViewModelListObservable().subscribe(newMotionblocks => {
newMotionblocks.sort((a, b) => (a > b ? 1 : -1));
this.dataSource.data = newMotionblocks;

View File

@ -73,6 +73,15 @@ export class MotionCommentSectionListComponent extends BaseViewComponent impleme
this.updateForm = this.formBuilder.group(form);
}
/**
* Init function.
*/
public ngOnInit(): void {
super.setTitle('Comment fields');
this.groups = this.groupRepo.getViewModelListBehaviorSubject();
this.repo.getViewModelListObservable().subscribe(newViewSections => (this.commentSections = newViewSections));
}
/**
* Event on Key Down in update or create form.
*
@ -96,16 +105,6 @@ export class MotionCommentSectionListComponent extends BaseViewComponent impleme
}
}
/**
* Init function.
*/
public ngOnInit(): void {
super.setTitle('Comment fields');
this.groups = new BehaviorSubject(this.groupRepo.getViewModelList());
this.groupRepo.getViewModelListObservable().subscribe(groups => this.groups.next(groups));
this.repo.getViewModelListObservable().subscribe(newViewSections => (this.commentSections = newViewSections));
}
/**
* Opens the create form.
*/

View File

@ -97,8 +97,7 @@ export class ManageSubmittersComponent extends BaseViewComponent {
this.addSubmitterForm.reset();
// get all users for the submitter add form
this.users = new BehaviorSubject<ViewUser[]>(this.userRepository.getViewModelList());
this.userRepository.getViewModelListObservable().subscribe(users => this.users.next(users));
this.users = this.userRepository.getViewModelListBehaviorSubject();
}
/**

View File

@ -494,7 +494,9 @@
mat-icon-button
[matMenuTriggerFor]="changeRecoMenu"
matTooltip="{{ 'Change recommendations' | translate }}"
*ngIf="motion && !motion.isParagraphBasedAmendment() && allChangingObjects.length > 0"
*ngIf="
motion && !motion.isParagraphBasedAmendment() && allChangingObjects && allChangingObjects.length > 0
"
>
<mat-icon>rate_review</mat-icon>
</button>
@ -503,7 +505,7 @@
type="button"
mat-icon-button
matTooltip="{{ 'Create final print template' | translate }}"
*osPerms="'motions.can_manage';and:isRecoMode(ChangeRecoMode.Final)"
*osPerms="'motions.can_manage'; and: isRecoMode(ChangeRecoMode.Final)"
(click)="createModifiedFinalVersion()"
>
<mat-icon>description</mat-icon>
@ -886,7 +888,7 @@
<button
mat-menu-item
translate
*osPerms="'motions.can_manage';and:isRecoMode(ChangeRecoMode.Final)"
*osPerms="'motions.can_manage'; and: isRecoMode(ChangeRecoMode.Final)"
(click)="setChangeRecoMode(ChangeRecoMode.ModifiedFinal)"
[ngClass]="{ selected: motion?.crMode === ChangeRecoMode.ModifiedFinal }"
>

View File

@ -1,4 +1,4 @@
import { ActivatedRoute, Router } from '@angular/router';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import { Component, OnInit, OnDestroy, ElementRef, HostListener, TemplateRef } from '@angular/core';
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser';
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
@ -12,15 +12,13 @@ import { CategoryRepositoryService } from 'app/core/repositories/motions/categor
import { ChangeRecommendationRepositoryService } from 'app/core/repositories/motions/change-recommendation-repository.service';
import { CreateMotion } from 'app/site/motions/models/create-motion';
import { ConfigService } from 'app/core/ui-services/config.service';
import { DataStoreService } from 'app/core/core-services/data-store.service';
import { DiffLinesInParagraph, LineRange } from 'app/core/ui-services/diff.service';
import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
import { itemVisibilityChoices, Item } from 'app/shared/models/agenda/item';
import { itemVisibilityChoices } from 'app/shared/models/agenda/item';
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
import { LocalPermissionsService } from 'app/site/motions/services/local-permissions.service';
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
import { Motion } from 'app/shared/models/motions/motion';
import { MotionBlock } from 'app/shared/models/motions/motion-block';
import {
MotionChangeRecommendationComponentData,
MotionChangeRecommendationComponent
@ -32,7 +30,6 @@ import { OperatorService } from 'app/core/core-services/operator.service';
import { PersonalNoteService } from 'app/core/ui-services/personal-note.service';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { StatuteParagraphRepositoryService } from 'app/core/repositories/motions/statute-paragraph-repository.service';
import { Tag } from 'app/shared/models/core/tag';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
import { ViewMotionBlock } from 'app/site/motions/models/view-motion-block';
import { ViewWorkflow } from 'app/site/motions/models/view-workflow';
@ -42,7 +39,6 @@ import { ViewCreateMotion } from 'app/site/motions/models/view-create-motion';
import { ViewItem } from 'app/site/agenda/models/view-item';
import { ViewportService } from 'app/core/ui-services/viewport.service';
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
import { ViewMotionChangeRecommendation } from 'app/site/motions/models/view-change-recommendation';
import {
ViewMotionNotificationEditMotion,
@ -52,7 +48,10 @@ import { ViewMotion, ChangeRecoMode, LineNumberingMode } from 'app/site/motions/
import { ViewStatuteParagraph } from 'app/site/motions/models/view-statute-paragraph';
import { ViewTag } from 'app/site/tags/models/view-tag';
import { ViewUnifiedChange } from 'app/shared/models/motions/view-unified-change';
import { Workflow } from 'app/shared/models/motions/workflow';
import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service';
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service';
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
/**
* Component for the motion detail view
@ -344,6 +343,13 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
*/
public backTarget = '../..';
/**
* Hold the subscription to the navigation.
* This cannot go into the subscription-list, since it should
* only get destroyed using ngOnDestroy routine and not on route changes.
*/
private navigationSubscription: Subscription;
/**
* Constructs the detail view.
*
@ -391,45 +397,44 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
private agendaRepo: ItemRepositoryService,
private changeRecoRepo: ChangeRecommendationRepositoryService,
private statuteRepo: StatuteParagraphRepositoryService,
private DS: DataStoreService,
private configService: ConfigService,
private sanitizer: DomSanitizer,
private promptService: PromptService,
private pdfExport: MotionPdfExportService,
private personalNoteService: PersonalNoteService,
private linenumberingService: LinenumberingService,
private viewModelStore: ViewModelStoreService,
private categoryRepo: CategoryRepositoryService,
private userRepo: UserRepositoryService,
private notifyService: NotifyService
private notifyService: NotifyService,
private tagRepo: TagRepositoryService,
private mediaFilerepo: MediafileRepositoryService,
private workflowRepo: WorkflowRepositoryService,
private blockRepo: MotionBlockRepositoryService,
private itemRepo: ItemRepositoryService
) {
super(title, translate, matSnackBar);
}
this.workflowObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewWorkflow));
this.blockObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewMotionBlock));
this.mediafilesObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewMediafile));
this.agendaItemObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewItem));
this.tagObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewTag));
this.motionObserver = new BehaviorSubject(this.viewModelStore.getAll(ViewMotion));
/**
* Init.
* Sets all required subjects and fills in the required information
*/
public ngOnInit(): void {
// get required information from the repositories
this.tagObserver = this.tagRepo.getViewModelListBehaviorSubject();
this.mediafilesObserver = this.mediaFilerepo.getViewModelListBehaviorSubject();
this.workflowObserver = this.workflowRepo.getViewModelListBehaviorSubject();
this.blockObserver = this.blockRepo.getViewModelListBehaviorSubject();
this.agendaItemObserver = this.itemRepo.getViewModelListBehaviorSubject();
this.motionObserver = this.repo.getViewModelListBehaviorSubject();
this.submitterObserver = this.userRepo.getViewModelListBehaviorSubject();
this.supporterObserver = this.userRepo.getViewModelListBehaviorSubject();
this.categoryObserver = this.categoryRepo.getViewModelListBehaviorSubject();
// Make sure the subjects are updated, when a new Model for the type arrives
// TODO get rid of DS here
this.DS.changeObservable.subscribe(newModel => {
if (newModel instanceof Workflow) {
this.workflowObserver.next(this.viewModelStore.getAll(ViewWorkflow));
} else if (newModel instanceof MotionBlock) {
this.blockObserver.next(this.viewModelStore.getAll(ViewMotionBlock));
} else if (newModel instanceof Mediafile) {
this.mediafilesObserver.next(this.viewModelStore.getAll(ViewMediafile));
} else if (newModel instanceof Item) {
this.agendaItemObserver.next(this.viewModelStore.getAll(ViewItem));
} else if (newModel instanceof Tag) {
this.tagObserver.next(this.viewModelStore.getAll(ViewTag));
} else if (newModel instanceof Motion) {
this.motionObserver.next(this.viewModelStore.getAll(ViewMotion));
this.setSurroundingMotions();
}
});
this.createForm();
this.observeRoute();
this.getMotionByUrl();
this.setSurroundingMotions();
// load config variables
this.configService
@ -452,36 +457,17 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
this.configService
.get<ChangeRecoMode>('motions_recommendation_text_mode')
.subscribe(mode => (this.crMode = mode));
}
/**
* Init.
* Sets the surrounding motions to navigate back and forth
*/
public ngOnInit(): void {
this.createForm();
this.getMotionByUrl();
this.setSurroundingMotions();
// TODO: Changed to un-sort, since it's a really heavy operation
this.userRepo.getViewModelListObservable().subscribe(unsortedUsers => {
this.submitterObserver.next(unsortedUsers);
this.supporterObserver.next(unsortedUsers);
});
this.categoryRepo.getViewModelListObservable().subscribe(unsortedCategories => {
this.categoryObserver.next(unsortedCategories);
});
// Initial Filling of the Subjects
this.submitterObserver = new BehaviorSubject(this.userRepo.getViewModelList());
this.supporterObserver = new BehaviorSubject(this.userRepo.getViewModelList());
this.categoryObserver = new BehaviorSubject(
this.categoryRepo.sortViewCategoriesByConfig(this.viewModelStore.getAll(ViewCategory))
);
this.statuteRepo.getViewModelListObservable().subscribe(newViewStatuteParagraphs => {
this.statuteParagraphs = newViewStatuteParagraphs;
// disable the selector for attachments if there are none
this.mediafilesObserver.subscribe(() => {
if (this.contentForm) {
const attachmentsCtrl = this.contentForm.get('attachments_id');
if (this.mediafilesObserver.value.length === 0) {
attachmentsCtrl.disable();
} else {
attachmentsCtrl.enable();
}
}
});
// Set the default visibility using observers
@ -491,15 +477,15 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
}
});
// disable the selector for attachments if there are none
this.mediafilesObserver.subscribe(files => {
if (this.createForm) {
const attachmentsCtrl = this.contentForm.get('attachments_id');
if (this.mediafilesObserver.value.length === 0) {
attachmentsCtrl.disable();
} else {
attachmentsCtrl.enable();
}
// Update statute paragraphs
this.statuteRepo.getViewModelListObservable().subscribe(newViewStatuteParagraphs => {
this.statuteParagraphs = newViewStatuteParagraphs;
});
// Observe motion changes to trigger surrounding motions
this.motionObserver.subscribe(motionChanges => {
if (motionChanges) {
this.setSurroundingMotions();
}
});
}
@ -510,6 +496,22 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
*/
public ngOnDestroy(): void {
this.unsubscribeEditNotifications(TypeOfNotificationViewMotion.TYPE_CLOSING_EDITING_MOTION);
if (this.navigationSubscription) {
this.navigationSubscription.unsubscribe();
}
}
/**
* Observes the route for events. Calls to clean all subs if the route changes.
* Calls the motion details from the new route
*/
public observeRoute(): void {
this.navigationSubscription = this.router.events.subscribe(navEvent => {
if (navEvent instanceof NavigationEnd) {
this.cleanSubjects();
this.getMotionByUrl();
}
});
}
/**
@ -555,65 +557,68 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
* determine the motion to display using the URL
*/
public getMotionByUrl(): void {
this.route.params.subscribe(params => {
if (Object.keys(params).length > 0) {
// load existing motion
const motionId: number = +params.id;
this.repo.getViewModelObservable(motionId).subscribe(newViewMotion => {
if (newViewMotion) {
this.motion = newViewMotion;
const params = this.route.snapshot.params;
if (params && params.id) {
// existing motion
const motionId: number = +params.id;
// the following subscriptions need to be cleared when the route changes
this.subscriptions.push(
this.repo.getViewModelObservable(motionId).subscribe(motion => {
if (motion) {
this.motion = motion;
this.newStateExtension = this.motion.stateExtension;
this.patchForm(this.motion);
}
});
}),
this.repo.amendmentsTo(motionId).subscribe(
(amendments: ViewMotion[]): void => {
this.amendments = amendments;
this.recalcUnifiedChanges();
}
);
),
this.changeRecoRepo
.getChangeRecosOfMotionObservable(motionId)
.subscribe((recos: ViewMotionChangeRecommendation[]) => {
this.changeRecommendations = recos;
this.recalcUnifiedChanges();
})
);
} else {
// new motion
this.newMotion = true;
this.editMotion = true;
// prevent 'undefined' to appear in the ui
const defaultMotion: Partial<CreateMotion> = {
title: '',
origin: '',
identifier: ''
};
if (this.route.snapshot.queryParams.parent) {
this.amendmentEdit = true;
const parentMotion = this.repo.getViewModel(this.route.snapshot.queryParams.parent);
const defaultTitle = `${this.translate.instant('Amendment to')} ${parentMotion.identifierOrTitle}`;
const mode = this.configService.instant<string>('motions_amendments_text_mode');
if (mode === 'freestyle' || mode === 'fulltext') {
defaultMotion.title = defaultTitle;
defaultMotion.parent_id = parentMotion.id;
defaultMotion.category_id = parentMotion.category_id;
defaultMotion.motion_block_id = parentMotion.motion_block_id;
this.contentForm.patchValue({
title: defaultTitle,
category_id: parentMotion.category_id,
motion_block_id: parentMotion.motion_block_id,
parent_id: parentMotion.id
});
} else {
// creates a new motion
this.newMotion = true;
this.editMotion = true;
// prevent 'undefined' to appear in the ui
const defaultMotion: Partial<CreateMotion> = {
title: '',
origin: '',
identifier: ''
};
if (this.route.snapshot.queryParams.parent) {
this.amendmentEdit = true;
const parentMotion = this.repo.getViewModel(this.route.snapshot.queryParams.parent);
const defaultTitle = `${this.translate.instant('Amendment to')} ${parentMotion.identifierOrTitle}`;
const mode = this.configService.instant<string>('motions_amendments_text_mode');
if (mode === 'freestyle' || mode === 'fulltext') {
defaultMotion.title = defaultTitle;
defaultMotion.parent_id = parentMotion.id;
defaultMotion.category_id = parentMotion.category_id;
defaultMotion.motion_block_id = parentMotion.motion_block_id;
this.contentForm.patchValue({
title: defaultTitle,
category_id: parentMotion.category_id,
motion_block_id: parentMotion.motion_block_id,
parent_id: parentMotion.id
});
}
if (mode === 'fulltext') {
defaultMotion.text = parentMotion.text;
this.contentForm.patchValue({ text: parentMotion.text });
}
}
this.motion = new ViewCreateMotion(new CreateMotion(defaultMotion));
this.motionCopy = new ViewCreateMotion(new CreateMotion(defaultMotion));
if (mode === 'fulltext') {
defaultMotion.text = parentMotion.text;
this.contentForm.patchValue({ text: parentMotion.text });
}
}
});
this.motion = new ViewCreateMotion(new CreateMotion(defaultMotion));
this.motionCopy = new ViewCreateMotion(new CreateMotion(defaultMotion));
}
}
/**
@ -1095,7 +1100,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
*/
public navigateToMotion(motion: ViewMotion): void {
if (motion) {
this.router.navigate(['../contacts'], { relativeTo: this.route.parent });
this.router.navigate([`../${motion.id}`], { relativeTo: this.route.parent });
// update the current motion
this.motion = motion;
this.setSurroundingMotions();
@ -1243,15 +1248,17 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
* Observes the repository for changes in the motion recommender
*/
public setupRecommender(): void {
const configKey = this.motion.isStatuteAmendment()
? 'motions_statute_recommendations_by'
: 'motions_recommendations_by';
if (this.recommenderSubscription) {
this.recommenderSubscription.unsubscribe();
if (this.motion) {
const configKey = this.motion.isStatuteAmendment()
? 'motions_statute_recommendations_by'
: 'motions_recommendations_by';
if (this.recommenderSubscription) {
this.recommenderSubscription.unsubscribe();
}
this.recommenderSubscription = this.configService.get<string>(configKey).subscribe(recommender => {
this.recommender = recommender;
});
}
this.recommenderSubscription = this.configService.get<string>(configKey).subscribe(recommender => {
this.recommender = recommender;
});
}
/**

View File

@ -5,7 +5,7 @@ import { MotionDetailComponent } from './components/motion-detail/motion-detail.
import { AmendmentCreateWizardComponent } from './components/amendment-create-wizard/amendment-create-wizard.component';
const routes: Routes = [
{ path: '', component: MotionDetailComponent, pathMatch: 'full' },
{ path: '', component: MotionDetailComponent, pathMatch: 'full', runGuardsAndResolvers: 'paramsChange' },
{ path: 'create-amendment', component: AmendmentCreateWizardComponent }
];

View File

@ -41,7 +41,8 @@ const routes: Routes = [
},
{
path: ':id',
loadChildren: './modules/motion-detail/motion-detail.module#MotionDetailModule'
loadChildren: './modules/motion-detail/motion-detail.module#MotionDetailModule',
runGuardsAndResolvers: 'paramsChange'
}
];

View File

@ -54,6 +54,10 @@ export class ViewCountdown extends BaseProjectableViewModel {
return this.description ? `${this.title} (${this.description})` : this.title;
};
public getModel(): Countdown {
return this.countdown;
}
public updateDependencies(update: BaseViewModel): void {}
public getSlide(): ProjectorElementBuildDeskriptor {

View File

@ -35,6 +35,10 @@ export class ViewProjectorMessage extends BaseProjectableViewModel {
return 'Message';
};
public getModel(): ProjectorMessage {
return this.projectormessage;
}
public updateDependencies(update: BaseViewModel): void {}
public getSlide(): ProjectorElementBuildDeskriptor {

View File

@ -106,6 +106,10 @@ export class ViewProjector extends BaseViewModel {
return this.name;
};
public getModel(): Projector {
return this.projector;
}
public updateDependencies(update: BaseViewModel): void {
if (update instanceof ViewProjector && this.reference_projector_id === update.id) {
this._referenceProjector = update;

View File

@ -41,6 +41,10 @@ export class ViewTag extends BaseViewModel implements Searchable {
return this.name;
};
public getModel(): Tag {
return this.tag;
}
public formatForSearch(): SearchRepresentation {
return [this.name];
}

View File

@ -107,7 +107,7 @@ export class GroupListComponent extends BaseViewComponent implements OnInit {
if (!this.groupForm.value || !this.groupForm.valid) {
return;
}
this.repo.create(this.groupForm.value).then(() => {
this.repo.create(this.groupForm.value as Group).then(() => {
this.groupForm.reset();
this.cancelEditing();
}, this.raiseError);

View File

@ -41,6 +41,10 @@ export class ViewCsvCreateUser extends ViewUser {
super(user);
}
public getModel(): User {
return super.getModel();
}
/**
* takes a list of solved group maps to update. Returns the amount of
* entries that remain unmatched

View File

@ -76,6 +76,10 @@ export class ViewGroup extends BaseViewModel {
return this.name;
};
public getModel(): Group {
return this.group;
}
public updateDependencies(update: BaseViewModel): void {
console.log('ViewGroups wants to update Values with : ', update);
}

View File

@ -36,5 +36,9 @@ export class ViewPersonalNote extends BaseViewModel {
return this.personalNote ? this.personalNote.toString() : null;
};
public getModel(): PersonalNote {
return this.personalNote;
}
public updateDependencies(update: BaseViewModel): void {}
}

View File

@ -179,6 +179,10 @@ export class ViewUser extends BaseProjectableViewModel implements Searchable {
this._groups = groups;
}
public getModel(): User {
return this.user;
}
/**
* Formats the category for search
*