Merge pull request #4150 from FinnStutzenstein/count-users

count users via notify
This commit is contained in:
Finn Stutzenstein 2019-02-02 10:45:52 +01:00 committed by GitHub
commit fa63110889
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 555 additions and 222 deletions

View File

@ -1,11 +1,13 @@
import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { OperatorService } from './core/core-services/operator.service';
import { LoginDataService } from './core/ui-services/login-data.service';
import { ConfigService } from './core/ui-services/config.service';
import { ConstantsService } from './core/ui-services/constants.service';
import { ServertimeService } from './core/core-services/servertime.service';
import { ThemeService } from './core/ui-services/theme.service';
import { CountUsersService } from './core/ui-services/count-users.service';
/**
* Angular's global App Component
@ -35,7 +37,8 @@ export class AppComponent {
loginDataService: LoginDataService,
constantsService: ConstantsService, // Needs to be started, so it can register itself to the WebsocketService
servertimeService: ServertimeService,
themeService: ThemeService
themeService: ThemeService,
countUsersService: CountUsersService // Needed to register itself.
) {
// manually add the supported languages
translate.addLangs(['en', 'de', 'cs']);

View File

@ -137,7 +137,6 @@ export class DataStoreService {
// This promise will be resolved with the maximal change id of the cache.
const store = await this.storageService.get<JsonStorage>(DataStoreService.cachePrefix + 'DS');
if (store) {
console.log('init from storage:', store);
// There is a store. Deserialize it
this.jsonStore = store;
this.modelStore = this.deserializeJsonStore(this.jsonStore);
@ -186,7 +185,6 @@ export class DataStoreService {
* Clears the complete DataStore and Cache.
*/
public async clear(): Promise<void> {
console.log('DS clear');
this.modelStore = {};
this.jsonStore = {};
this._maxChangeId = 0;

View File

@ -120,8 +120,11 @@ export class NotifyService extends OpenSlidesComponent {
* @param content The payload to send.
* @param channels Multiple channels to send this message to.
*/
public sendToChannels<T>(name: string, content: T, ...channles: string[]): void {
this.send(name, content, null, channles);
public sendToChannels<T>(name: string, content: T, ...channels: string[]): void {
if (channels.length < 1) {
throw new Error('You have to provide at least one channel');
}
this.send(name, content, null, channels);
}
/**

View File

@ -74,7 +74,6 @@ export class OpenSlidesService extends OpenSlidesComponent {
public async afterLoginBootup(userId: number): Promise<void> {
// Else, check, which user was logged in last time
const lastUserId = await this.storageService.get<number>('lastUserLoggedIn');
console.log('user transition:', lastUserId, '->', userId);
// if the user changed, reset the cache and save the new user.
if (userId !== lastUserId) {
await this.DS.clear();
@ -88,7 +87,6 @@ export class OpenSlidesService extends OpenSlidesComponent {
*/
private async setupDataStoreAndWebSocket(): Promise<void> {
let changeId = await this.DS.initFromStorage();
console.log('change ID on DS setup', changeId);
if (changeId > 0) {
changeId += 1;
}

View File

@ -112,7 +112,6 @@ export class WebsocketService {
socketPath += window.location.hostname + ':' + window.location.port + '/ws/';
socketPath += formatQueryParams(queryParams);
console.log('connect to', socketPath);
this.websocket = new WebSocket(socketPath);
// connection established. If this connect attept was a retry,

View File

@ -3,20 +3,20 @@ import { tap, map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { BaseRepository } from '../base-repository';
import { AgendaBaseModel } from '../../../shared/models/base/agenda-base-model';
import { BaseModel } from '../../../shared/models/base/base-model';
import { AgendaBaseModel } from 'app/shared/models/base/agenda-base-model';
import { BaseModel } from 'app/shared/models/base/base-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 '../../../shared/models/base/identifiable';
import { Item } from '../../../shared/models/agenda/item';
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 { Speaker } from 'app/shared/models/agenda/speaker';
import { User } from 'app/shared/models/users/user';
import { ViewItem } from '../../../site/agenda/models/view-item';
import { ViewSpeaker } from '../../../site/agenda/models/view-speaker';
import { ViewItem } from 'app/site/agenda/models/view-item';
import { ViewSpeaker } from 'app/site/agenda/models/view-speaker';
import { TreeService } from 'app/core/ui-services/tree.service';
/**

View File

@ -6,10 +6,10 @@ import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
import { Item } from 'app/shared/models/agenda/item';
import { DataStoreService } from 'app/core/core-services/data-store.service';
import { DataSendService } from 'app/core/core-services/data-send.service';
import { ViewTopic } from '../../../site/agenda/models/view-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 '../../../site/agenda/models/create-topic';
import { CreateTopic } from 'app/site/agenda/models/create-topic';
/**
* Repository for topics

View File

@ -1,12 +1,12 @@
import { Injectable } from '@angular/core';
import { ViewAssignment } from '../../../site/assignments/models/view-assignment';
import { Assignment } from '../../../shared/models/assignments/assignment';
import { User } from '../../../shared/models/users/user';
import { Tag } from '../../../shared/models/core/tag';
import { Item } from '../../../shared/models/agenda/item';
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 { BaseRepository } from '../base-repository';
import { DataStoreService } from '../../core-services/data-store.service';
import { Identifiable } from '../../../shared/models/base/identifiable';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
/**

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { Identifiable } from '../../../shared/models/base/identifiable';
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';

View File

@ -7,7 +7,7 @@ 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 '../../../site/history/models/view-history';
import { ViewHistory } from 'app/site/history/models/view-history';
import { TimeTravelService } from 'app/core/core-services/time-travel.service';
import { BaseModel } from 'app/shared/models/base/base-model';

View File

@ -1,11 +1,11 @@
import { Injectable } from '@angular/core';
import { BaseRepository } from '../base-repository';
import { ViewMediafile } from '../../../site/mediafiles/models/view-mediafile';
import { Mediafile } from '../../../shared/models/mediafiles/mediafile';
import { User } from '../../../shared/models/users/user';
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
import { User } from 'app/shared/models/users/user';
import { DataStoreService } from '../../core-services/data-store.service';
import { Identifiable } from '../../../shared/models/base/identifiable';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { DataSendService } from 'app/core/core-services/data-send.service';
import { HttpService } from 'app/core/core-services/http.service';

View File

@ -1,13 +1,13 @@
import { Injectable } from '@angular/core';
import { Category } from '../../../shared/models/motions/category';
import { ViewCategory } from '../../../site/motions/models/view-category';
import { Category } from 'app/shared/models/motions/category';
import { ViewCategory } from 'app/site/motions/models/view-category';
import { DataSendService } from '../../core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { Motion } from '../../../shared/models/motions/motion';
import { Motion } from 'app/shared/models/motions/motion';
import { HttpService } from '../../core-services/http.service';
import { Identifiable } from '../../../shared/models/base/identifiable';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
/**

View File

@ -4,14 +4,14 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { DataSendService } from '../../core-services/data-send.service';
import { User } from '../../../shared/models/users/user';
import { Category } from '../../../shared/models/motions/category';
import { Workflow } from '../../../shared/models/motions/workflow';
import { User } from 'app/shared/models/users/user';
import { Category } from 'app/shared/models/motions/category';
import { Workflow } from 'app/shared/models/motions/workflow';
import { BaseRepository } from '../base-repository';
import { DataStoreService } from '../../core-services/data-store.service';
import { MotionChangeReco } from '../../../shared/models/motions/motion-change-reco';
import { ViewChangeReco } from '../../../site/motions/models/view-change-reco';
import { Identifiable } from '../../../shared/models/base/identifiable';
import { MotionChangeReco } from 'app/shared/models/motions/motion-change-reco';
import { ViewChangeReco } from 'app/site/motions/models/view-change-reco';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
/**

View File

@ -12,8 +12,8 @@ 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';
import { ViewMotion } from '../../../site/motions/models/view-motion';
import { ViewMotionBlock } from '../../../site/motions/models/view-motion-block';
import { ViewMotion } from 'app/site/motions/models/view-motion';
import { ViewMotionBlock } from 'app/site/motions/models/view-motion-block';
/**
* Repository service for motion blocks

View File

@ -3,10 +3,10 @@ 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 { ViewMotionCommentSection } from '../../../site/motions/models/view-motion-comment-section';
import { MotionCommentSection } from '../../../shared/models/motions/motion-comment-section';
import { Group } from '../../../shared/models/users/group';
import { Identifiable } from '../../../shared/models/base/identifiable';
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';

View File

@ -5,21 +5,21 @@ import { Observable } from 'rxjs';
import { tap, map } from 'rxjs/operators';
import { BaseRepository } from '../base-repository';
import { Category } from '../../../shared/models/motions/category';
import { ChangeRecoMode, ViewMotion } from '../../../site/motions/models/view-motion';
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 '../../../site/motions/models/create-motion';
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 '../../../shared/models/base/identifiable';
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';
import { Motion } from '../../../shared/models/motions/motion';
import { Motion } from 'app/shared/models/motions/motion';
import { MotionBlock } from 'app/shared/models/motions/motion-block';
import { MotionChangeReco } from '../../../shared/models/motions/motion-change-reco';
import { MotionChangeReco } from 'app/shared/models/motions/motion-change-reco';
import { MotionPoll } from 'app/shared/models/motions/motion-poll';
import { OSTreeSortEvent } from 'app/shared/components/sorting-tree/sorting-tree.component';
import { PersonalNoteService } from '../../ui-services/personal-note.service';

View File

@ -3,9 +3,9 @@ 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 { ViewStatuteParagraph } from '../../../site/motions/models/view-statute-paragraph';
import { StatuteParagraph } from '../../../shared/models/motions/statute-paragraph';
import { Identifiable } from '../../../shared/models/base/identifiable';
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';
/**

View File

@ -1,14 +1,14 @@
import { Injectable } from '@angular/core';
import { Workflow } from '../../../shared/models/motions/workflow';
import { ViewWorkflow } from '../../../site/motions/models/view-workflow';
import { Workflow } from 'app/shared/models/motions/workflow';
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 '../../../shared/models/base/identifiable';
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 '../../../site/motions/models/view-motion';
import { ViewMotion } from 'app/site/motions/models/view-motion';
/**
* Repository Services for Categories

View File

@ -2,10 +2,10 @@ 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 '../../../shared/models/base/identifiable';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ViewCountdown } from '../../../site/projector/models/view-countdown';
import { Countdown } from '../../../shared/models/core/countdown';
import { ViewCountdown } from 'app/site/projector/models/view-countdown';
import { Countdown } from 'app/shared/models/core/countdown';
@Injectable({
providedIn: 'root'

View File

@ -4,9 +4,9 @@ import { BaseRepository } from '../base-repository';
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 { ViewProjector } from '../../../site/projector/models/view-projector';
import { Projector } from '../../../shared/models/core/projector';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { ViewProjector } from 'app/site/projector/models/view-projector';
import { Projector } from 'app/shared/models/core/projector';
import { HttpService } from 'app/core/core-services/http.service';
/**

View File

@ -1,10 +1,10 @@
import { Injectable } from '@angular/core';
import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository';
import { Identifiable } from '../../../shared/models/base/identifiable';
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 '../../../site/projector/models/view-projectormessage';
import { ViewProjectorMessage } from 'app/site/projector/models/view-projectormessage';
@Injectable({
providedIn: 'root'

View File

@ -1,11 +1,11 @@
import { Injectable } from '@angular/core';
import { Tag } from '../../../shared/models/core/tag';
import { ViewTag } from '../../../site/tags/models/view-tag';
import { Tag } from 'app/shared/models/core/tag';
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 '../../../shared/models/base/identifiable';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
/**

View File

@ -5,9 +5,9 @@ import { CollectionStringMapperService } from '../../core-services/collectionStr
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 '../../../shared/models/users/group';
import { Identifiable } from '../../../shared/models/base/identifiable';
import { ViewGroup } from '../../../site/users/models/view-group';
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';
/**
* Shape of a permission

View File

@ -1,12 +1,12 @@
import { Injectable } from '@angular/core';
import { BaseRepository } from '../base-repository';
import { ViewUser } from '../../../site/users/models/view-user';
import { User } from '../../../shared/models/users/user';
import { Group } from '../../../shared/models/users/group';
import { ViewUser } from 'app/site/users/models/view-user';
import { User } from 'app/shared/models/users/user';
import { Group } from 'app/shared/models/users/group';
import { DataStoreService } from '../../core-services/data-store.service';
import { DataSendService } from '../../core-services/data-send.service';
import { Identifiable } from '../../../shared/models/base/identifiable';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { HttpService } from 'app/core/core-services/http.service';

View File

@ -0,0 +1,17 @@
import { TestBed, inject } from '@angular/core/testing';
import { E2EImportsModule } from '../../../e2e-imports.module';
import { CountUsersService } from './count-users.service';
describe('CountUsersService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [E2EImportsModule],
providers: [CountUsersService]
});
});
it('should be created', inject([CountUsersService], (service: CountUsersService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,107 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { OpenSlidesComponent } from 'app/openslides.component';
import { NotifyService } from '../core-services/notify.service';
import { OperatorService } from '../core-services/operator.service';
interface CountUserRequest {
token: string;
}
interface CountUserResponse extends CountUserRequest {
userId: number;
}
const REQUEST_NAME = 'count-user-request';
const RESPONSE_NAME = 'count-user-response';
/**
* Provides functionality to count users with notify.
* Sends requests to all active instances, which (hopefully) respond to this message.
* Here, the answers will be collected and aggegated.
*/
@Injectable({
providedIn: 'root'
})
export class CountUsersService extends OpenSlidesComponent {
private activeCounts: { [token: string]: Subject<number> } = {};
private currentUserId: number;
/**
* Sets up all listeners
*
* @param notifyService
* @param operator
*/
public constructor(private notifyService: NotifyService, operator: OperatorService) {
super();
// Listen for requests to send an answer.
this.notifyService.getMessageObservable<CountUserRequest>(REQUEST_NAME).subscribe(request => {
if (request.content.token) {
this.notifyService.sendToChannels(
RESPONSE_NAME,
{
token: request.content.token,
userId: this.currentUserId
},
request.senderChannelName
);
}
});
// Listen for responses and distribute them through `activeCounts`
this.notifyService.getMessageObservable<CountUserResponse>(RESPONSE_NAME).subscribe(response => {
if (response.content.userId && response.content.token && this.activeCounts[response.content.token]) {
this.activeCounts[response.content.token].next(response.content.userId);
}
});
// Look for the current user.
operator.getObservable().subscribe(user => (this.currentUserId = user ? user.id : null));
}
/**
* @returns a generated track token to keep track of the counting.
*/
private generateTrackToken(): string {
let token = '';
const characters = '0123456789abcdef';
for (let i = 0; i < 32; i++) {
token += characters.charAt(Math.floor(Math.random() * characters.length));
}
return token;
}
/**
* Starts the counting process
*
* @returns a tuple: the first entry is a token, which can be used to stop the
* counting with `stopCounting`. The second entry is an observable, where all user
* ids will be published.
*/
public countUsers(): [string, Observable<number>] {
const trackToken = this.generateTrackToken();
const subject = new Subject<number>();
this.activeCounts[trackToken] = subject;
this.notifyService.sendToAllUsers<CountUserRequest>(REQUEST_NAME, {
token: trackToken
});
return [trackToken, this.activeCounts[trackToken].asObservable()];
}
/**
* Stops an active counting by the provided token
*
* @param token The count to stop
*/
public stopCounting(trackToken: string): void {
if (this.activeCounts[trackToken]) {
this.activeCounts[trackToken].complete();
delete this.activeCounts[trackToken];
}
}
}

View File

@ -4,8 +4,8 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { MatDialogRef, MatDialog } from '@angular/material';
import { OperatorService } from '../../../core/core-services/operator.service';
import { NotifyService, NotifyResponse } from '../../../core/core-services/notify.service';
import { OperatorService } from 'app/core/core-services/operator.service';
import { NotifyService, NotifyResponse } from 'app/core/core-services/notify.service';
import { Subscription } from 'rxjs';
/**

View File

@ -2,8 +2,8 @@ import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Location } from '@angular/common';
import { Router, ActivatedRoute } from '@angular/router';
import { ViewportService } from '../../../core/ui-services/viewport.service';
import { MainMenuService } from '../../../core/core-services/main-menu.service';
import { ViewportService } from 'app/core/ui-services/viewport.service';
import { MainMenuService } from 'app/core/core-services/main-menu.service';
/**
* Reusable head bar component for Apps.

View File

@ -2,9 +2,9 @@ import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { LoginDataService } from '../../../core/ui-services/login-data.service';
import { LoginDataService } from 'app/core/ui-services/login-data.service';
import { environment } from 'environments/environment';
import { HttpService } from '../../../core/core-services/http.service';
import { HttpService } from 'app/core/core-services/http.service';
/**
* Characterize a plugin. This data is retrieved from the server

View File

@ -1,6 +1,6 @@
import { Component, OnInit, Input } from '@angular/core';
import { MediaManageService } from '../../../core/ui-services/media-manage.service';
import { MediaManageService } from 'app/core/ui-services/media-manage.service';
import { ConfigService } from 'app/core/ui-services/config.service';
/**

View File

@ -1,7 +1,7 @@
import { Component, Input } from '@angular/core';
import { BaseComponent } from '../../../base.component';
import { ViewportService } from '../../../core/ui-services/viewport.service';
import { ViewportService } from 'app/core/ui-services/viewport.service';
/**
* Component for the motion comments view

View File

@ -1,4 +1,5 @@
import { Output, Component, OnInit, EventEmitter, Input } from '@angular/core';
import { BaseFilterListService, OsFilterOption } from 'app/core/ui-services/base-filter-list.service';
/**

View File

@ -1,7 +1,8 @@
import { Inject, Component, OnInit } from '@angular/core';
import { MatBottomSheetRef, MAT_BOTTOM_SHEET_DATA } from '@angular/material';
import { BaseViewModel } from '../../../../site/base/base-view-model';
import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service';
import { BaseViewModel } from 'app/site/base/base-view-model';
/**
* A bottom sheet used for setting a list's sorting, used by {@link SortFilterBarComponent}

View File

@ -3,12 +3,12 @@ import { MatBottomSheet } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';
import { BaseViewModel } from '../../../site/base/base-view-model';
import { BaseViewModel } from 'app/site/base/base-view-model';
import { OsSortBottomSheetComponent } from './os-sort-bottom-sheet/os-sort-bottom-sheet.component';
import { FilterMenuComponent } from './filter-menu/filter-menu.component';
import { OsSortingItem } from '../../../core/ui-services/base-sort-list.service';
import { BaseSortListService } from '../../../core/ui-services/base-sort-list.service';
import { ViewportService } from '../../../core/ui-services/viewport.service';
import { OsSortingItem } from 'app/core/ui-services/base-sort-list.service';
import { BaseSortListService } from 'app/core/ui-services/base-sort-list.service';
import { ViewportService } from 'app/core/ui-services/viewport.service';
/**
* Reusable bar for list views, offering sorting and filter options.

View File

@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { LoginDataService } from '../../../core/ui-services/login-data.service';
import { LoginDataService } from 'app/core/ui-services/login-data.service';
/**
* Shared component to hold the content of the Privacy Policy.

View File

@ -1,7 +1,7 @@
import { AssignmentUser } from './assignment-user';
import { Poll } from './poll';
import { AgendaBaseModel } from '../base/agenda-base-model';
import { SearchRepresentation } from '../../../core/ui-services/search.service';
import { SearchRepresentation } from 'app/core/ui-services/search.service';
export const assignmentPhase = [
{ key: 0, name: 'Searching for candidates' },

View File

@ -1,6 +1,6 @@
import { AgendaInformation } from './agenda-information';
import { Searchable } from './searchable';
import { SearchRepresentation } from '../../../core/ui-services/search.service';
import { SearchRepresentation } from 'app/core/ui-services/search.service';
import { BaseModel } from './base-model';
/**

View File

@ -1,5 +1,5 @@
import { DetailNavigable } from './detail-navigable';
import { SearchRepresentation } from '../../../core/ui-services/search.service';
import { SearchRepresentation } from 'app/core/ui-services/search.service';
/**
* Asserts, if the given object is searchable.

View File

@ -1,6 +1,6 @@
import { BaseModel } from '../base/base-model';
import { Searchable } from '../base/searchable';
import { SearchRepresentation } from '../../../core/ui-services/search.service';
import { SearchRepresentation } from 'app/core/ui-services/search.service';
/**
* Representation of a motion category. Has the nested property "File"

View File

@ -1,5 +1,5 @@
import { AgendaBaseModel } from '../base/agenda-base-model';
import { SearchRepresentation } from '../../../core/ui-services/search.service';
import { SearchRepresentation } from 'app/core/ui-services/search.service';
/**
* Representation of a motion block.

View File

@ -1,7 +1,7 @@
import { MotionSubmitter } from './motion-submitter';
import { MotionComment } from './motion-comment';
import { AgendaBaseModel } from '../base/agenda-base-model';
import { SearchRepresentation } from '../../../core/ui-services/search.service';
import { SearchRepresentation } from 'app/core/ui-services/search.service';
import { MotionPoll } from './motion-poll';
/**

View File

@ -1,6 +1,6 @@
import { BaseModel } from '../base/base-model';
import { Searchable } from '../base/searchable';
import { SearchRepresentation } from '../../../core/ui-services/search.service';
import { SearchRepresentation } from 'app/core/ui-services/search.service';
/**
* Representation of a statute paragraph.

View File

@ -1,5 +1,5 @@
import { AgendaBaseModel } from '../base/agenda-base-model';
import { SearchRepresentation } from '../../../core/ui-services/search.service';
import { SearchRepresentation } from 'app/core/ui-services/search.service';
/**
* Representation of a topic.

View File

@ -1,5 +1,5 @@
import { Searchable } from '../base/searchable';
import { SearchRepresentation } from '../../../core/ui-services/search.service';
import { SearchRepresentation } from 'app/core/ui-services/search.service';
import { BaseModel } from '../base/base-model';
import { DetailNavigable } from '../base/detail-navigable';

View File

@ -1,6 +1,6 @@
import { BaseViewModel } from '../../base/base-view-model';
import { Item } from '../../../shared/models/agenda/item';
import { AgendaBaseModel } from '../../../shared/models/base/agenda-base-model';
import { Item } from 'app/shared/models/agenda/item';
import { AgendaBaseModel } from 'app/shared/models/base/agenda-base-model';
import { Speaker } from 'app/shared/models/agenda/speaker';
export class ViewItem extends BaseViewModel {

View File

@ -1,10 +1,10 @@
import { Injectable } from '@angular/core';
import { BaseFilterListService, OsFilter, OsFilterOption } from '../../../core/ui-services/base-filter-list.service';
import { Item, itemVisibilityChoices } from '../../../shared/models/agenda/item';
import { BaseFilterListService, OsFilter, OsFilterOption } from 'app/core/ui-services/base-filter-list.service';
import { Item, itemVisibilityChoices } from 'app/shared/models/agenda/item';
import { ViewItem } from '../models/view-item';
import { StorageService } from 'app/core/core-services/storage.service';
import { AgendaRepositoryService } from '../../../core/repositories/agenda/agenda-repository.service';
import { AgendaRepositoryService } from 'app/core/repositories/agenda/agenda-repository.service';
@Injectable({
providedIn: 'root'

View File

@ -4,9 +4,9 @@ import { TranslateService } from '@ngx-translate/core';
import { Title } from '@angular/platform-browser';
import { AssignmentFilterListService } from '../services/assignment-filter.service';
import { AssignmentRepositoryService } from '../../../core/repositories/assignments/assignment-repository.service';
import { AssignmentRepositoryService } from 'app/core/repositories/assignments/assignment-repository.service';
import { ListViewBaseComponent } from '../../base/list-view-base';
import { PromptService } from '../../../core/ui-services/prompt.service';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { ViewAssignment } from '../models/view-assignment';
import { AssignmentSortListService } from '../services/assignment-sort-list.service';

View File

@ -1,8 +1,8 @@
import { BaseViewModel } from '../../base/base-view-model';
import { Assignment } from '../../../shared/models/assignments/assignment';
import { Tag } from '../../../shared/models/core/tag';
import { User } from '../../../shared/models/users/user';
import { Item } from '../../../shared/models/agenda/item';
import { Assignment } from 'app/shared/models/assignments/assignment';
import { Tag } from 'app/shared/models/core/tag';
import { User } from 'app/shared/models/users/user';
import { Item } from 'app/shared/models/agenda/item';
export class ViewAssignment extends BaseViewModel {
private _assignment: Assignment;

View File

@ -1,8 +1,8 @@
import { Injectable } from '@angular/core';
import { AssignmentRepositoryService } from '../../../core/repositories/assignments/assignment-repository.service';
import { Assignment, assignmentPhase } from '../../../shared/models/assignments/assignment';
import { BaseFilterListService, OsFilter, OsFilterOption } from '../../../core/ui-services/base-filter-list.service';
import { AssignmentRepositoryService } from 'app/core/repositories/assignments/assignment-repository.service';
import { Assignment, assignmentPhase } from 'app/shared/models/assignments/assignment';
import { BaseFilterListService, OsFilter, OsFilterOption } from 'app/core/ui-services/base-filter-list.service';
import { StorageService } from 'app/core/core-services/storage.service';
import { ViewAssignment } from '../models/view-assignment';

View File

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { BaseSortListService, OsSortingDefinition } from '../../../core/ui-services/base-sort-list.service';
import { BaseSortListService, OsSortingDefinition } from 'app/core/ui-services/base-sort-list.service';
import { ViewAssignment } from '../models/view-assignment';
@Injectable({

View File

@ -7,11 +7,10 @@ import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-poli
import { StartComponent } from './components/start/start.component';
import { LegalNoticeComponent } from './components/legal-notice/legal-notice.component';
import { SearchComponent } from './components/search/search.component';
import { CountdownRepositoryService } from '../../core/repositories/projector/countdown-repository.service';
import { CountUsersComponent } from './components/count-users/count-users.component';
@NgModule({
providers: [CountdownRepositoryService],
imports: [AngularCommonModule, CommonRoutingModule, SharedModule],
declarations: [PrivacyPolicyComponent, StartComponent, LegalNoticeComponent, SearchComponent]
declarations: [PrivacyPolicyComponent, StartComponent, LegalNoticeComponent, SearchComponent, CountUsersComponent]
})
export class CommonModule {}

View File

@ -0,0 +1,22 @@
<mat-card class="os-card" *osPerms="'users.can_manage'">
<button type="button" mat-button (click)="countUsers()" *ngIf="!this.token">
<span translate>Count active users</span>
</button>
<button type="button" mat-button (click)="stopCounting()" *ngIf="this.token">
<span translate>Stop counting</span>
</button>
<div *ngIf="stats">
<p>
{{ userIds().length }} <span translate>active users</span>
({{ stats.activeUserHandles }} <span translate>connections</span>)
</p>
<h3 translate>Groups</h3>
<ul>
<li *ngFor="let groupId of groupIds()">
<strong>{{ stats.groups[groupId].name }}</strong>:
{{ userInGroupIds(groupId).length }} <span translate>active users</span>
({{ stats.groups[groupId].userHandleCount }} <span translate>connections</span>)
</li>
</ul>
</div>
</mat-card>

View File

@ -0,0 +1,26 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CountUsersComponent } from './count-users.component';
import { E2EImportsModule } from '../../../../../e2e-imports.module';
describe('CountUsersComponent', () => {
let component: CountUsersComponent;
let fixture: ComponentFixture<CountUsersComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [E2EImportsModule],
declarations: [CountUsersComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CountUsersComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,55 @@
import { Component, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs';
import { auditTime } from 'rxjs/operators';
import { CountUsersStatisticsService, CountUserStatistics } from '../../services/count-user-statistics.service';
/**
* This component provides an interface to count users
*/
@Component({
selector: 'os-count-users',
templateUrl: './count-users.component.html'
})
export class CountUsersComponent implements OnDestroy {
public token: string = null;
public stats: CountUserStatistics = null;
public constructor(private countUsersStatisticService: CountUsersStatisticsService) {}
public countUsers(): void {
if (this.token) {
return;
}
let statsObservable: Observable<CountUserStatistics>;
[this.token, statsObservable] = this.countUsersStatisticService.countUsers();
statsObservable.pipe(auditTime(100)).subscribe(stats => {
this.stats = stats;
});
}
public stopCounting(): void {
if (this.token) {
this.countUsersStatisticService.stopCounting(this.token);
this.token = null;
this.stats = null;
}
}
public userIds(): number[] {
return Object.keys(this.stats.activeUsers).map(id => +id);
}
public groupIds(): number[] {
return Object.keys(this.stats.groups).map(id => +id);
}
public userInGroupIds(groupId: number): number[] {
return Object.keys(this.stats.groups[groupId].users).map(id => +id);
}
public ngOnDestroy(): void {
this.stopCounting();
}
}

View File

@ -5,3 +5,5 @@
</os-head-bar>
<os-legal-notice-content></os-legal-notice-content>
<os-count-users></os-count-users>

View File

@ -2,6 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LegalNoticeComponent } from './legal-notice.component';
import { E2EImportsModule } from '../../../../../e2e-imports.module';
import { CountUsersComponent } from '../count-users/count-users.component';
describe('LegalNoticeComponent', () => {
let component: LegalNoticeComponent;
@ -10,7 +11,7 @@ describe('LegalNoticeComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [E2EImportsModule],
declarations: [LegalNoticeComponent]
declarations: [LegalNoticeComponent, CountUsersComponent]
}).compileComponents();
}));

View File

@ -1,12 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
@Component({
selector: 'os-legal-notice',
templateUrl: './legal-notice.component.html',
styleUrls: ['./legal-notice.component.scss']
templateUrl: './legal-notice.component.html'
})
export class LegalNoticeComponent implements OnInit {
export class LegalNoticeComponent {
public constructor() {}
public ngOnInit(): void {}
}

View File

@ -5,7 +5,7 @@ import { BaseComponent } from 'app/base.component';
import { TranslateService } from '@ngx-translate/core'; // showcase
// for testing the DS and BaseModel
import { Config } from '../../../../shared/models/core/config';
import { Config } from 'app/shared/models/core/config';
import { DataStoreService } from 'app/core/core-services/data-store.service';
@Component({

View File

@ -0,0 +1,102 @@
import { Injectable } from '@angular/core';
import { OpenSlidesComponent } from 'app/openslides.component';
import { CountUsersService } from 'app/core/ui-services/count-users.service';
import { Observable, BehaviorSubject } from 'rxjs';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
/**
* The format of the count statistic
*/
export interface CountUserStatistics {
activeUserHandles: number;
activeUsers: {
[id: number]: number;
};
groups: {
[id: number]: {
name: string;
users: {
[id: number]: number;
};
userHandleCount: number;
};
};
}
/**
* Provides statistics for counting users
*/
@Injectable({
providedIn: 'root'
})
export class CountUsersStatisticsService extends OpenSlidesComponent {
private runningCounts: { [token: string]: BehaviorSubject<CountUserStatistics> } = {};
public constructor(private countUserService: CountUsersService, private userRepo: UserRepositoryService) {
super();
}
/**
* Starts counting users.
*
* @returns a 2-tuple: A token to stop the counting with `stopCounting` and
* an observable where the statistics are published.
*/
public countUsers(): [string, Observable<CountUserStatistics>] {
let token: string;
let userIdObservable: Observable<number>;
// Start counting
// TODO: maybe we shold bet the observable bofore the actual countig was
// started. We might miss some user ids.
[token, userIdObservable] = this.countUserService.countUsers();
this.runningCounts[token] = new BehaviorSubject<CountUserStatistics>({
activeUserHandles: 0,
activeUsers: {},
groups: {}
});
// subscribe to responses
userIdObservable.subscribe(userId => {
const stats = this.runningCounts[token].getValue();
const user = this.userRepo.getViewModel(userId);
// Add to user stats
stats.activeUserHandles++;
if (!stats.activeUsers[userId]) {
stats.activeUsers[userId] = 0;
}
stats.activeUsers[userId]++;
// Add to group stats
const groups = user ? user.groups : [];
groups.forEach(group => {
if (!stats.groups[group.id]) {
stats.groups[group.id] = {
name: group.name,
users: {},
userHandleCount: 0
};
}
stats.groups[group.id].userHandleCount++;
stats.groups[group.id].users[userId] = stats.activeUsers[userId];
});
this.runningCounts[token].next(stats);
});
return [token, this.runningCounts[token].asObservable()];
}
/**
* Stop an active count.
*
* @param token The token to identify the current count
*/
public stopCounting(token: string): void {
if (this.runningCounts[token]) {
this.runningCounts[token].complete();
delete this.runningCounts[token];
}
}
}

View File

@ -8,7 +8,7 @@ import { ViewConfig } from '../../models/view-config';
import { BaseComponent } from '../../../../base.component';
import { FormGroup, FormBuilder } from '@angular/forms';
import { ConfigRepositoryService } from '../../services/config-repository.service';
import { ParentErrorStateMatcher } from '../../../../shared/parent-error-state-matcher';
import { ParentErrorStateMatcher } from 'app/shared/parent-error-state-matcher';
/**
* List view for the categories.

View File

@ -1,5 +1,5 @@
import { BaseViewModel } from '../../base/base-view-model';
import { Config } from '../../../shared/models/core/config';
import { Config } from 'app/shared/models/core/config';
interface ConfigChoice {
value: string;

View File

@ -1,14 +1,14 @@
import { Injectable } from '@angular/core';
import { BaseRepository } from '../../../core/repositories/base-repository';
import { BaseRepository } from 'app/core/repositories/base-repository';
import { ViewConfig } from '../models/view-config';
import { Config } from '../../../shared/models/core/config';
import { Config } from 'app/shared/models/core/config';
import { Observable, BehaviorSubject } from 'rxjs';
import { DataStoreService } from '../../../core/core-services/data-store.service';
import { ConstantsService } from '../../../core/ui-services/constants.service';
import { HttpService } from '../../../core/core-services/http.service';
import { Identifiable } from '../../../shared/models/base/identifiable';
import { CollectionStringMapperService } from '../../../core/core-services/collectionStringMapper.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';
/**
* Holds a single config item.

View File

@ -9,7 +9,7 @@ import { TranslateService } from '@ngx-translate/core';
import { environment } from 'environments/environment';
import { OpenSlidesService } from 'app/core/core-services/openslides.service';
import { LoginDataService } from 'app/core/ui-services/login-data.service';
import { ParentErrorStateMatcher } from '../../../../shared/parent-error-state-matcher';
import { ParentErrorStateMatcher } from 'app/shared/parent-error-state-matcher';
import { HttpService } from 'app/core/core-services/http.service';
/**

View File

@ -1,6 +1,6 @@
import { BaseViewModel } from '../../base/base-view-model';
import { Mediafile } from '../../../shared/models/mediafiles/mediafile';
import { User } from '../../../shared/models/users/user';
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
import { User } from 'app/shared/models/users/user';
export class ViewMediafile extends BaseViewModel {
private _mediafile: Mediafile;

View File

@ -1,10 +1,10 @@
import { Injectable } from '@angular/core';
import { BaseFilterListService, OsFilter } from '../../../core/ui-services/base-filter-list.service';
import { Mediafile } from '../../../shared/models/mediafiles/mediafile';
import { BaseFilterListService, OsFilter } from 'app/core/ui-services/base-filter-list.service';
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
import { ViewMediafile } from '../models/view-mediafile';
import { StorageService } from 'app/core/core-services/storage.service';
import { MediafileRepositoryService } from '../../../core/repositories/mediafiles/mediafile-repository.service';
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
@Injectable({
providedIn: 'root'

View File

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { BaseSortListService, OsSortingDefinition } from '../../../core/ui-services/base-sort-list.service';
import { BaseSortListService, OsSortingDefinition } from 'app/core/ui-services/base-sort-list.service';
import { ViewMediafile } from '../models/view-mediafile';
@Injectable({

View File

@ -3,12 +3,12 @@ import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { Category } from '../../../../shared/models/motions/category';
import { Category } from 'app/shared/models/motions/category';
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
import { ViewCategory } from '../../models/view-category';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Motion } from '../../../../shared/models/motions/motion';
import { SortingListComponent } from '../../../../shared/components/sorting-list/sorting-list.component';
import { Motion } from 'app/shared/models/motions/motion';
import { SortingListComponent } from 'app/shared/components/sorting-list/sorting-list.component';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { BaseViewComponent } from '../../../base/base-view';
import { MatSnackBar } from '@angular/material';

View File

@ -6,11 +6,11 @@ import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject } from 'rxjs';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MotionCommentSection } from '../../../../shared/models/motions/motion-comment-section';
import { MotionCommentSection } from 'app/shared/models/motions/motion-comment-section';
import { ViewMotionCommentSection } from '../../models/view-motion-comment-section';
import { MotionCommentSectionRepositoryService } from 'app/core/repositories/motions/motion-comment-section-repository.service';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { Group } from '../../../../shared/models/users/group';
import { Group } from 'app/shared/models/users/group';
import { DataStoreService } from 'app/core/core-services/data-store.service';
import { BaseViewComponent } from '../../../base/base-view';

View File

@ -5,12 +5,12 @@ import { FormGroup, FormBuilder } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { BaseViewComponent } from '../../../../site/base/base-view';
import { MotionCommentSectionRepositoryService } from 'app/core/repositories/motions/motion-comment-section-repository.service';
import { ViewMotionCommentSection } from '../../models/view-motion-comment-section';
import { OperatorService } from 'app/core/core-services/operator.service';
import { MotionComment } from '../../../../shared/models/motions/motion-comment';
import { MotionComment } from 'app/shared/models/motions/motion-comment';
import { ViewMotion } from '../../models/view-motion';
import { BaseViewComponent } from 'app/site/base/base-view';
/**
* Component for the motion comments view

View File

@ -10,7 +10,7 @@ import { TranslateService } from '@ngx-translate/core';
import { AgendaRepositoryService } from 'app/core/repositories/agenda/agenda-repository.service';
import { BaseViewComponent } from '../../../base/base-view';
import { Category } from '../../../../shared/models/motions/category';
import { Category } from 'app/shared/models/motions/category';
import { ChangeRecommendationRepositoryService } from 'app/core/repositories/motions/change-recommendation-repository.service';
import { ChangeRecoMode, LineNumberingMode, ViewMotion } from '../../models/view-motion';
import { CreateMotion } from '../../models/create-motion';
@ -20,7 +20,7 @@ import { DiffLinesInParagraph, LineRange } from 'app/core/ui-services/diff.servi
import { itemVisibilityChoices, Item } from 'app/shared/models/agenda/item';
import { LocalPermissionsService } from '../../services/local-permissions.service';
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
import { Motion } from '../../../../shared/models/motions/motion';
import { Motion } from 'app/shared/models/motions/motion';
import { MotionBlock } from 'app/shared/models/motions/motion-block';
import {
MotionChangeRecommendationComponent,
@ -32,7 +32,7 @@ import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
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 { User } from '../../../../shared/models/users/user';
import { User } from 'app/shared/models/users/user';
import { ViewChangeReco } from '../../models/view-change-reco';
import { ViewCreateMotion } from '../../models/view-create-motion';
import { ViewportService } from 'app/core/ui-services/viewport.service';

View File

@ -21,7 +21,7 @@ import { ViewMotion } from '../../models/view-motion';
import { ViewMotionBlock } from '../../models/view-motion-block';
import { ViewTag } from 'app/site/tags/models/view-tag';
import { ViewWorkflow } from '../../models/view-workflow';
import { WorkflowState } from '../../../../shared/models/motions/workflow-state';
import { WorkflowState } from 'app/shared/models/motions/workflow-state';
import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service';
import { MotionPdfExportService } from '../../services/motion-pdf-export.service';
import { MotionExportDialogComponent } from '../motion-export-dialog/motion-export-dialog.component';

View File

@ -6,7 +6,7 @@ import { Subscription } from 'rxjs';
import { BaseComponent } from '../../../../base.component';
import { ViewMotion } from '../../models/view-motion';
import { PersonalNoteService } from 'app/core/ui-services/personal-note.service';
import { PersonalNoteContent } from '../../../../shared/models/users/personal-note';
import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
/**
* Component for the motion comments view

View File

@ -6,7 +6,7 @@ import { MatSnackBar } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { StatuteParagraph } from '../../../../shared/models/motions/statute-paragraph';
import { StatuteParagraph } from 'app/shared/models/motions/statute-paragraph';
import { ViewStatuteParagraph } from '../../models/view-statute-paragraph';
import { StatuteParagraphRepositoryService } from 'app/core/repositories/motions/statute-paragraph-repository.service';
import { BaseViewComponent } from '../../../base/base-view';

View File

@ -1,4 +1,4 @@
import { Category } from '../../../shared/models/motions/category';
import { Category } from 'app/shared/models/motions/category';
import { BaseViewModel } from '../../base/base-view-model';
/**

View File

@ -1,7 +1,7 @@
import { BaseViewModel } from '../../base/base-view-model';
import { MotionChangeReco } from '../../../shared/models/motions/motion-change-reco';
import { BaseModel } from '../../../shared/models/base/base-model';
import { ModificationType } from '../../../core/ui-services/diff.service';
import { MotionChangeReco } from 'app/shared/models/motions/motion-change-reco';
import { BaseModel } from 'app/shared/models/base/base-model';
import { ModificationType } from 'app/core/ui-services/diff.service';
import { ViewUnifiedChange, ViewUnifiedChangeType } from './view-unified-change';
/**

View File

@ -1,7 +1,7 @@
import { Category } from '../../../shared/models/motions/category';
import { User } from '../../../shared/models/users/user';
import { Workflow } from '../../../shared/models/motions/workflow';
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
import { Category } from 'app/shared/models/motions/category';
import { User } from 'app/shared/models/users/user';
import { Workflow } from 'app/shared/models/motions/workflow';
import { WorkflowState } from 'app/shared/models/motions/workflow-state';
import { Item } from 'app/shared/models/agenda/item';
import { MotionBlock } from 'app/shared/models/motions/motion-block';
import { ViewMotion } from './view-motion';

View File

@ -1,7 +1,7 @@
import { ViewUnifiedChange, ViewUnifiedChangeType } from './view-unified-change';
import { ViewMotion } from './view-motion';
import { LineRange } from '../../../core/ui-services/diff.service';
import { MergeAmendment } from '../../../shared/models/motions/workflow-state';
import { LineRange } from 'app/core/ui-services/diff.service';
import { MergeAmendment } from 'app/shared/models/motions/workflow-state';
/**
* This represents the Unified Diff part of an amendments.

View File

@ -1,7 +1,7 @@
import { BaseViewModel } from '../../base/base-view-model';
import { MotionCommentSection } from '../../../shared/models/motions/motion-comment-section';
import { Group } from '../../../shared/models/users/group';
import { BaseModel } from '../../../shared/models/base/base-model';
import { MotionCommentSection } from 'app/shared/models/motions/motion-comment-section';
import { Group } from 'app/shared/models/users/group';
import { BaseModel } from 'app/shared/models/base/base-model';
/**
* Motion comment section class for the View

View File

@ -1,16 +1,16 @@
import { BaseModel } from '../../../shared/models/base/base-model';
import { BaseModel } from 'app/shared/models/base/base-model';
import { BaseProjectableModel } from 'app/site/base/base-projectable-model';
import { Category } from '../../../shared/models/motions/category';
import { MotionComment } from '../../../shared/models/motions/motion-comment';
import { Category } from 'app/shared/models/motions/category';
import { MotionComment } from 'app/shared/models/motions/motion-comment';
import { Item } from 'app/shared/models/agenda/item';
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
import { Motion } from '../../../shared/models/motions/motion';
import { Motion } from 'app/shared/models/motions/motion';
import { MotionBlock } from 'app/shared/models/motions/motion-block';
import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
import { User } from '../../../shared/models/users/user';
import { User } from 'app/shared/models/users/user';
import { ViewMotionCommentSection } from './view-motion-comment-section';
import { Workflow } from '../../../shared/models/motions/workflow';
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
import { Workflow } from 'app/shared/models/motions/workflow';
import { WorkflowState } from 'app/shared/models/motions/workflow-state';
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
import { Tag } from 'app/shared/models/core/tag';

View File

@ -1,7 +1,7 @@
import { BaseViewModel } from '../../base/base-view-model';
import { Group } from '../../../shared/models/users/group';
import { BaseModel } from '../../../shared/models/base/base-model';
import { StatuteParagraph } from '../../../shared/models/motions/statute-paragraph';
import { Group } from 'app/shared/models/users/group';
import { BaseModel } from 'app/shared/models/base/base-model';
import { StatuteParagraph } from 'app/shared/models/motions/statute-paragraph';
/**
* State paragrpah class for the View

View File

@ -1,5 +1,5 @@
import { Workflow } from '../../../shared/models/motions/workflow';
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
import { Workflow } from 'app/shared/models/motions/workflow';
import { WorkflowState } from 'app/shared/models/motions/workflow-state';
import { BaseViewModel } from '../../base/base-view-model';
/**

View File

@ -1,8 +1,8 @@
import { Injectable } from '@angular/core';
import { OperatorService } from '../../../core/core-services/operator.service';
import { OperatorService } from 'app/core/core-services/operator.service';
import { ViewMotion } from '../models/view-motion';
import { ConfigService } from '../../../core/ui-services/config.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { ConstantsService } from 'app/core/ui-services/constants.service';
interface OpenSlidesSettings {

View File

@ -1,14 +1,14 @@
import { Injectable } from '@angular/core';
import { BaseFilterListService, OsFilter, OsFilterOption } from '../../../core/ui-services/base-filter-list.service';
import { Motion } from '../../../shared/models/motions/motion';
import { BaseFilterListService, OsFilter, OsFilterOption } from 'app/core/ui-services/base-filter-list.service';
import { Motion } from 'app/shared/models/motions/motion';
import { ViewMotion } from '../models/view-motion';
import { CategoryRepositoryService } from '../../../core/repositories/motions/category-repository.service';
import { WorkflowRepositoryService } from '../../../core/repositories/motions/workflow-repository.service';
import { StorageService } from '../../../core/core-services/storage.service';
import { MotionRepositoryService } from '../../../core/repositories/motions/motion-repository.service';
import { MotionBlockRepositoryService } from '../../../core/repositories/motions/motion-block-repository.service';
import { MotionCommentSectionRepositoryService } from '../../../core/repositories/motions/motion-comment-section-repository.service';
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service';
import { StorageService } from 'app/core/core-services/storage.service';
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
import { MotionCommentSectionRepositoryService } from 'app/core/repositories/motions/motion-comment-section-repository.service';
import { TranslateService } from '@ngx-translate/core';
import { ConfigService } from 'app/core/ui-services/config.service';
import { ViewWorkflow } from '../models/view-workflow';

View File

@ -5,12 +5,12 @@ import { Papa } from 'ngx-papaparse';
import { TranslateService } from '@ngx-translate/core';
import { Category } from 'app/shared/models/motions/category';
import { CategoryRepositoryService } from '../../../core/repositories/motions/category-repository.service';
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
import { CreateMotion } from '../models/create-motion';
import { MotionBlock } from 'app/shared/models/motions/motion-block';
import { MotionBlockRepositoryService } from '../../../core/repositories/motions/motion-block-repository.service';
import { MotionRepositoryService } from '../../../core/repositories/motions/motion-repository.service';
import { UserRepositoryService } from '../../../core/repositories/users/user-repository.service';
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
import { ViewCsvCreateMotion, CsvMapping } from '../models/view-csv-create-motion';
import { BaseImportService, NewEntry } from 'app/core/ui-services/base-import.service';
import { ViewMotion } from '../models/view-motion';

View File

@ -5,16 +5,16 @@ import { TranslateService } from '@ngx-translate/core';
import { ViewMotion } from '../models/view-motion';
import { ChoiceService } from 'app/core/ui-services/choice.service';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { MotionRepositoryService } from '../../../core/repositories/motions/motion-repository.service';
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
import { WorkflowRepositoryService } from '../../../core/repositories/motions/workflow-repository.service';
import { CategoryRepositoryService } from '../../../core/repositories/motions/category-repository.service';
import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service';
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service';
import { HttpService } from 'app/core/core-services/http.service';
import { AgendaRepositoryService } from 'app/core/repositories/agenda/agenda-repository.service';
import { Displayable } from 'app/shared/models/base/displayable';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { MotionBlockRepositoryService } from '../../../core/repositories/motions/motion-block-repository.service';
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
/**
* Contains all multiselect actions for the motion list view.

View File

@ -2,13 +2,12 @@ import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ChangeRecommendationRepositoryService } from '../../../core/repositories/motions/change-recommendation-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { MotionRepositoryService } from '../../../core/repositories/motions/motion-repository.service';
import { HtmlToPdfService } from 'app/core/ui-services/html-to-pdf.service';
import { ViewMotion, LineNumberingMode, ChangeRecoMode } from '../models/view-motion';
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { ChangeRecommendationRepositoryService } from 'app/core/repositories/motions/change-recommendation-repository.service';
import { ViewUnifiedChange } from '../models/view-unified-change';
import { HtmlToPdfService } from 'app/core/ui-services/html-to-pdf.service';
/**
* Converts a motion to pdf. Can be used from the motion detail view or executed on a list of motions
* Provides the public method `motionToDocDef(motion: Motion)` which should be convenient to use.

View File

@ -4,7 +4,7 @@ import { TranslateService } from '@ngx-translate/core';
import { ConfigService } from 'app/core/ui-services/config.service';
import { MotionPoll } from 'app/shared/models/motions/motion-poll';
import { MotionRepositoryService } from '../../../core/repositories/motions/motion-repository.service';
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
import { PdfDocumentService } from 'app/core/ui-services/pdf-document.service';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { BaseSortListService, OsSortingDefinition } from '../../../core/ui-services/base-sort-list.service';
import { BaseSortListService, OsSortingDefinition } from 'app/core/ui-services/base-sort-list.service';
import { ViewMotion } from '../models/view-motion';
@Injectable({

View File

@ -1,4 +1,4 @@
import { Countdown } from '../../../shared/models/core/countdown';
import { Countdown } from 'app/shared/models/core/countdown';
import { BaseProjectableModel } from 'app/site/base/base-projectable-model';
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';

View File

@ -1,7 +1,7 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Title } from '@angular/platform-browser';
import { Tag } from '../../../../shared/models/core/tag';
import { Tag } from 'app/shared/models/core/tag';
import { ListViewBaseComponent } from '../../../base/list-view-base';
import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service';
import { ViewTag } from '../../models/view-tag';

View File

@ -1,4 +1,4 @@
import { Tag } from '../../../shared/models/core/tag';
import { Tag } from 'app/shared/models/core/tag';
import { BaseViewModel } from '../../base/base-view-model';
/**

View File

@ -6,7 +6,7 @@ import { FormGroup, FormControl, Validators } from '@angular/forms';
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
import { ViewGroup } from '../../models/view-group';
import { Group } from '../../../../shared/models/users/group';
import { Group } from 'app/shared/models/users/group';
import { BaseViewComponent } from '../../../base/base-view';
import { PromptService } from 'app/core/ui-services/prompt.service';

View File

@ -8,7 +8,7 @@ import { Title } from '@angular/platform-browser';
import { ViewUser } from '../../models/view-user';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
import { OperatorService } from 'app/core/core-services/operator.service';
import { BaseViewComponent } from '../../../../site/base/base-view';
import { BaseViewComponent } from 'app/site/base/base-view';
/**
* Component for the Password-Reset Handling

View File

@ -9,7 +9,7 @@ import { TranslateService } from '@ngx-translate/core';
import { BaseViewComponent } from '../../../base/base-view';
import { DataStoreService } from 'app/core/core-services/data-store.service';
import { genders } from 'app/shared/models/users/user';
import { Group } from '../../../../shared/models/users/group';
import { Group } from 'app/shared/models/users/group';
import { OperatorService } from 'app/core/core-services/operator.service';
import { PromptService } from 'app/core/ui-services/prompt.service';
import { UserPdfExportService } from '../../services/user-pdf-export.service';

View File

@ -1,6 +1,6 @@
import { BaseViewModel } from '../../base/base-view-model';
import { Group } from '../../../shared/models/users/group';
import { BaseModel } from '../../../shared/models/base/base-model';
import { Group } from 'app/shared/models/users/group';
import { BaseModel } from 'app/shared/models/base/base-model';
export class ViewGroup extends BaseViewModel {
private _group: Group;

View File

@ -1,6 +1,6 @@
import { User } from '../../../shared/models/users/user';
import { Group } from '../../../shared/models/users/group';
import { BaseModel } from '../../../shared/models/base/base-model';
import { User } from 'app/shared/models/users/user';
import { Group } from 'app/shared/models/users/group';
import { BaseModel } from 'app/shared/models/base/base-model';
import { BaseProjectableModel } from 'app/site/base/base-projectable-model';
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';

View File

@ -1,11 +1,11 @@
import { Injectable } from '@angular/core';
import { BaseFilterListService, OsFilter } from '../../../core/ui-services/base-filter-list.service';
import { StorageService } from '../../../core/core-services/storage.service';
import { User } from '../../../shared/models/users/user';
import { BaseFilterListService, OsFilter } from 'app/core/ui-services/base-filter-list.service';
import { StorageService } from 'app/core/core-services/storage.service';
import { User } from 'app/shared/models/users/user';
import { ViewUser } from '../models/view-user';
import { GroupRepositoryService } from '../../../core/repositories/users/group-repository.service';
import { UserRepositoryService } from '../../../core/repositories/users/user-repository.service';
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
@Injectable({
providedIn: 'root'

View File

@ -4,10 +4,10 @@ import { Papa } from 'ngx-papaparse';
import { BaseImportService, NewEntry } from 'app/core/ui-services/base-import.service';
import { Group } from 'app/shared/models/users/group';
import { GroupRepositoryService } from '../../../core/repositories/users/group-repository.service';
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
import { TranslateService } from '@ngx-translate/core';
import { User } from 'app/shared/models/users/user';
import { UserRepositoryService } from '../../../core/repositories/users/user-repository.service';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
import { ViewCsvCreateUser, CsvMapping } from '../models/view-csv-create-user';
import { ViewUser } from '../models/view-user';

View File

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { BaseSortListService, OsSortingDefinition } from '../../../core/ui-services/base-sort-list.service';
import { BaseSortListService, OsSortingDefinition } from 'app/core/ui-services/base-sort-list.service';
import { ViewUser } from '../models/view-user';
@Injectable({