diff --git a/client/src/app/gateways/repositories/meeting_user/meeting-user-repository.service.ts b/client/src/app/gateways/repositories/meeting_user/meeting-user-repository.service.ts index a4b1f290c0..4498ec3608 100644 --- a/client/src/app/gateways/repositories/meeting_user/meeting-user-repository.service.ts +++ b/client/src/app/gateways/repositories/meeting_user/meeting-user-repository.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { Id } from 'src/app/domain/definitions/key-types'; import { MeetingUser } from 'src/app/domain/models/meeting-users/meeting-user'; import { toDecimal } from 'src/app/infrastructure/utils'; import { ViewMeetingUser } from 'src/app/site/pages/meetings/view-models/view-meeting-user'; @@ -17,6 +18,8 @@ export type MeetingUserPatchFn = export class MeetingUserRepositoryService extends BaseMeetingRelatedRepository { public override readonly resetOnMeetingChange = false; + private meetingUserIdMap: Map> = new Map(); + public constructor(repositoryServiceCollector: RepositoryMeetingServiceCollectorService) { super(repositoryServiceCollector, MeetingUser); } @@ -66,4 +69,40 @@ export class MeetingUserRepositoryService extends BaseMeetingRelatedRepository viewUser.user?.getTitle() ?? `Unknown`; public getVerboseName = (plural = false): string => this.translate.instant(plural ? `Participants` : `Participant`); + + public getMeetingUserId(userId: Id, meetingId: Id): Id | null { + if (this.meetingUserIdMap.has(userId) && this.meetingUserIdMap.get(userId).has(meetingId)) { + return this.meetingUserIdMap.get(userId).get(meetingId); + } + + return null; + } + + public override deleteModels(ids: Id[]): void { + ids.forEach(id => { + const user = this.viewModelStore[id]; + if (user && user.user_id && user.meeting_id) { + const meetingUserId = this.meetingUserIdMap.get(user.user_id)?.get(user.meeting_id); + if (meetingUserId === user.id) { + this.meetingUserIdMap.get(user.user_id).delete(user.meeting_id); + } + } + }); + super.deleteModels(ids); + } + + protected override clearViewModelStore(): void { + super.clearViewModelStore(); + this.meetingUserIdMap = new Map(); + } + + protected override onCreateViewModel(meetingUser: ViewMeetingUser): void { + if (meetingUser.user_id && meetingUser.meeting_id) { + if (!this.meetingUserIdMap.has(meetingUser.user_id)) { + this.meetingUserIdMap.set(meetingUser.user_id, new Map()); + } + + this.meetingUserIdMap.get(meetingUser.user_id).set(meetingUser.meeting_id, meetingUser.id); + } + } } diff --git a/client/src/app/gateways/repositories/users/user-repository.service.ts b/client/src/app/gateways/repositories/users/user-repository.service.ts index 5b8444dd94..d056099961 100644 --- a/client/src/app/gateways/repositories/users/user-repository.service.ts +++ b/client/src/app/gateways/repositories/users/user-repository.service.ts @@ -338,26 +338,17 @@ export class UserRepositoryService extends BaseRepository { protected override createViewModel(model: User): ViewUser { const viewModel = super.createViewModel(model); - const meetingUserIdMap = new Map(); - const getMeetingUserId = (meetingId: Id) => { - if (!meetingUserIdMap.has(meetingId)) { - for (const meetingUser of this.relationManager.handleRelation( - viewModel.getModel(), - this.relationsByKey[`meeting_users`] - )) { - meetingUserIdMap.set(meetingUser.meeting_id, meetingUser.id); - } - } - - return meetingUserIdMap.get(meetingId); - }; - - viewModel.getName = () => this.getName(viewModel); - viewModel.getShortName = () => this.getShortName(viewModel); - viewModel.getFullName = (structureLevel?: ViewStructureLevel) => this.getFullName(viewModel, structureLevel); - viewModel.getMeetingUser = (meetingId: Id) => this.getMeetingUser(getMeetingUserId, meetingId); - viewModel.getLevelAndNumber = () => this.getLevelAndNumber(viewModel); - viewModel.getEnsuredActiveMeetingId = () => this.activeMeetingIdService.meetingId; + viewModel.getName = (): string => this.getName(viewModel); + viewModel.getShortName = (): string => this.getShortName(viewModel); + viewModel.getFullName = (structureLevel?: ViewStructureLevel): string => + this.getFullName(viewModel, structureLevel); + viewModel.getMeetingUser = (meetingId: Id): ViewMeetingUser => + this.getMeetingUser( + (meetingId: Id): Id => this.meetingUserRepo.getMeetingUserId(model.id, meetingId), + meetingId + ); + viewModel.getLevelAndNumber = (): string => this.getLevelAndNumber(viewModel); + viewModel.getEnsuredActiveMeetingId = (): Id => this.activeMeetingIdService.meetingId; return viewModel; } diff --git a/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts b/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts index 1b03dc0009..d6e7914935 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts +++ b/client/src/app/site/pages/meetings/pages/agenda/agenda.subscription.ts @@ -1,5 +1,5 @@ import { Id } from 'src/app/domain/definitions/key-types'; -import { FULL_FIELDSET, MEETING_ROUTING_FIELDS, mergeSubscriptionFollow } from 'src/app/domain/fieldsets/misc'; +import { FULL_FIELDSET, MEETING_ROUTING_FIELDS } from 'src/app/domain/fieldsets/misc'; import { MeetingUserFieldsets, UserFieldsets } from 'src/app/domain/fieldsets/user'; import { SubscriptionConfigGenerator } from 'src/app/domain/interfaces/subscription-config'; import { ViewMeeting } from 'src/app/site/pages/meetings/view-models/view-meeting'; @@ -23,21 +23,7 @@ export const agendaItemFollow: FollowList = [ idField: `speaker_ids`, fieldset: FULL_FIELDSET, follow: [ - mergeSubscriptionFollow( - { - idField: `meeting_user_id`, - follow: [ - mergeSubscriptionFollow( - { idField: `user_id`, ...UserFieldsets.FullNameSubscription }, - { - idField: `user_id`, - fieldset: [`meeting_user_ids`] - } - ) - ] - }, - { idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription } - ), + { idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription }, { idField: `point_of_order_category_id`, fieldset: FULL_FIELDSET @@ -72,23 +58,7 @@ export const getAgendaListSubscriptionConfig: SubscriptionConfigGenerator = (id: { idField: `submitter_ids`, fieldset: FULL_FIELDSET, - follow: [ - mergeSubscriptionFollow( - { - idField: `meeting_user_id`, - follow: [ - mergeSubscriptionFollow( - { idField: `user_id`, ...UserFieldsets.FullNameSubscription }, - { - idField: `user_id`, - fieldset: [`meeting_user_ids`] - } - ) - ] - }, - { idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription } - ) - ] + follow: [{ idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription }] } ] } diff --git a/client/src/app/site/pages/meetings/pages/assignments/assignments.subscription.ts b/client/src/app/site/pages/meetings/pages/assignments/assignments.subscription.ts index 867b587be1..ba69e5432f 100644 --- a/client/src/app/site/pages/meetings/pages/assignments/assignments.subscription.ts +++ b/client/src/app/site/pages/meetings/pages/assignments/assignments.subscription.ts @@ -1,6 +1,5 @@ import { Id } from 'src/app/domain/definitions/key-types'; -import { mergeSubscriptionFollow } from 'src/app/domain/fieldsets/misc'; -import { MeetingUserFieldsets, UserFieldsets } from 'src/app/domain/fieldsets/user'; +import { MeetingUserFieldsets } from 'src/app/domain/fieldsets/user'; import { SubscriptionConfigGenerator } from 'src/app/domain/interfaces/subscription-config'; import { ViewMeeting } from 'src/app/site/pages/meetings/view-models/view-meeting'; @@ -24,23 +23,7 @@ export const getAssignmentSubscriptionConfig: SubscriptionConfigGenerator = (id: }, { idField: `assignment_candidate_ids`, - follow: [ - mergeSubscriptionFollow( - { - idField: `meeting_user_id`, - follow: [ - mergeSubscriptionFollow( - { idField: `user_id`, ...UserFieldsets.FullNameSubscription }, - { - idField: `user_id`, - fieldset: [`meeting_user_ids`] - } - ) - ] - }, - { idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription } - ) - ] + follow: [{ idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription }] } ] }, diff --git a/client/src/app/site/pages/meetings/pages/autopilot/autopilot.subscription.ts b/client/src/app/site/pages/meetings/pages/autopilot/autopilot.subscription.ts index 61875bedb6..985b33fb6e 100644 --- a/client/src/app/site/pages/meetings/pages/autopilot/autopilot.subscription.ts +++ b/client/src/app/site/pages/meetings/pages/autopilot/autopilot.subscription.ts @@ -1,6 +1,6 @@ import { Id } from 'src/app/domain/definitions/key-types'; import { FULL_FIELDSET, MEETING_ROUTING_FIELDS, mergeSubscriptionFollow } from 'src/app/domain/fieldsets/misc'; -import { MeetingUserFieldsets, UserFieldsets } from 'src/app/domain/fieldsets/user'; +import { MeetingUserFieldsets } from 'src/app/domain/fieldsets/user'; import { SubscriptionConfig, SubscriptionConfigGenerator } from 'src/app/domain/interfaces/subscription-config'; import { ViewMeeting } from 'src/app/site/pages/meetings/view-models/view-meeting'; @@ -61,13 +61,6 @@ export const getAutopilotContentSubscriptionConfig = (id: Id): SubscriptionConfi { idField: `meeting_user_id`, follow: [ - mergeSubscriptionFollow( - { idField: `user_id`, ...UserFieldsets.FullNameSubscription }, - { - idField: `user_id`, - fieldset: [`meeting_user_ids`] - } - ), { idField: `structure_level_ids`, fieldset: [`name`, `color`] diff --git a/client/src/app/site/pages/meetings/pages/motions/motions.subscription.ts b/client/src/app/site/pages/meetings/pages/motions/motions.subscription.ts index 910c1d4c6d..da79017e59 100644 --- a/client/src/app/site/pages/meetings/pages/motions/motions.subscription.ts +++ b/client/src/app/site/pages/meetings/pages/motions/motions.subscription.ts @@ -1,6 +1,6 @@ import { Id } from 'src/app/domain/definitions/key-types'; -import { FULL_FIELDSET, mergeSubscriptionFollow } from 'src/app/domain/fieldsets/misc'; -import { MeetingUserFieldsets, UserFieldsets } from 'src/app/domain/fieldsets/user'; +import { FULL_FIELDSET } from 'src/app/domain/fieldsets/misc'; +import { MeetingUserFieldsets } from 'src/app/domain/fieldsets/user'; import { SubscriptionConfigGenerator } from 'src/app/domain/interfaces/subscription-config'; import { ViewMeeting } from 'src/app/site/pages/meetings/view-models/view-meeting'; @@ -72,65 +72,17 @@ export const getMotionListSubscriptionConfig: SubscriptionConfigGenerator = (id: { idField: `submitter_ids`, fieldset: FULL_FIELDSET, - follow: [ - mergeSubscriptionFollow( - { - idField: `meeting_user_id`, - follow: [ - mergeSubscriptionFollow( - { idField: `user_id`, ...UserFieldsets.FullNameSubscription }, - { - idField: `user_id`, - fieldset: [`meeting_user_ids`] - } - ) - ] - }, - { idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription } - ) - ] + follow: [{ idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription }] }, { idField: `editor_ids`, fieldset: FULL_FIELDSET, - follow: [ - mergeSubscriptionFollow( - { - idField: `meeting_user_id`, - follow: [ - mergeSubscriptionFollow( - { idField: `user_id`, ...UserFieldsets.FullNameSubscription }, - { - idField: `user_id`, - fieldset: [`meeting_user_ids`] - } - ) - ] - }, - { idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription } - ) - ] + follow: [{ idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription }] }, { idField: `working_group_speaker_ids`, fieldset: FULL_FIELDSET, - follow: [ - mergeSubscriptionFollow( - { - idField: `meeting_user_id`, - follow: [ - mergeSubscriptionFollow( - { idField: `user_id`, ...UserFieldsets.FullNameSubscription }, - { - idField: `user_id`, - fieldset: [`meeting_user_ids`] - } - ) - ] - }, - { idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription } - ) - ] + follow: [{ idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription }] } ] } diff --git a/client/src/app/site/pages/meetings/pages/participants/participants.subscription.ts b/client/src/app/site/pages/meetings/pages/participants/participants.subscription.ts index 510fbbe773..5187a92018 100644 --- a/client/src/app/site/pages/meetings/pages/participants/participants.subscription.ts +++ b/client/src/app/site/pages/meetings/pages/participants/participants.subscription.ts @@ -1,6 +1,6 @@ import { Id } from 'src/app/domain/definitions/key-types'; -import { FULL_FIELDSET, MEETING_ROUTING_FIELDS, mergeSubscriptionFollow } from 'src/app/domain/fieldsets/misc'; -import { MeetingUserFieldsets, UserFieldsets } from 'src/app/domain/fieldsets/user'; +import { FULL_FIELDSET, MEETING_ROUTING_FIELDS } from 'src/app/domain/fieldsets/misc'; +import { MeetingUserFieldsets } from 'src/app/domain/fieldsets/user'; import { SubscriptionConfigGenerator } from 'src/app/domain/interfaces/subscription-config'; import { ViewMeeting } from 'src/app/site/pages/meetings/view-models/view-meeting'; import { DEFAULT_FIELDSET } from 'src/app/site/services/model-request-builder'; @@ -32,13 +32,12 @@ export const getParticipantVoteInfoSubscriptionConfig: SubscriptionConfigGenerat `is_physical_person`, `is_active`, `meeting_ids`, - `meeting_user_ids`, `is_present_in_meeting_ids` ] }, { idField: `vote_delegated_to_id`, - follow: [{ idField: `user_id`, fieldset: [`is_present_in_meeting_ids`, `meeting_user_ids`] }], + follow: [{ idField: `user_id`, fieldset: [`is_present_in_meeting_ids`] }], fieldset: [`meeting_id`] } ] @@ -138,13 +137,7 @@ export const getSpeakersListSubscriptionConfig: SubscriptionConfigGenerator = (i idField: `speaker_ids`, fieldset: FULL_FIELDSET, follow: [ - mergeSubscriptionFollow( - { - idField: `meeting_user_id`, - follow: [{ idField: `user_id`, ...UserFieldsets.FullNameSubscription }] - }, - { idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription } - ), + { idField: `meeting_user_id`, ...MeetingUserFieldsets.FullNameSubscription }, { idField: `structure_level_list_of_speakers_id`, fieldset: [], diff --git a/client/src/app/worker/sw-autoupdate.ts b/client/src/app/worker/sw-autoupdate.ts index 64524b6a54..0bd5eb9521 100644 --- a/client/src/app/worker/sw-autoupdate.ts +++ b/client/src/app/worker/sw-autoupdate.ts @@ -19,6 +19,7 @@ const subscriptionQueues: { [key: string]: AutoupdateSubscription[] } = { required: [], requiredMeeting: [], sequentialnumbermapping: [], + detail: [], other: [] }; const openTimeouts = { @@ -77,7 +78,7 @@ function openConnection( function getRequestCategory( description: string, _request: unknown - ): 'required' | 'requiredMeeting' | 'other' | 'sequentialnumbermapping' { + ): 'required' | 'requiredMeeting' | 'other' | 'sequentialnumbermapping' | null { const required = [`theme_list:subscription`, `operator:subscription`, `organization:subscription`]; if (required.indexOf(description) !== -1) { return `required`; @@ -92,6 +93,12 @@ function openConnection( return `sequentialnumbermapping`; } + // Subscriptions ending with a number nomally are used for detail subscriptions + // and should not be bundled + if (!isNaN(+description.substring(description.length - 13, description.length - 14))) { + return null; + } + return `other`; } @@ -123,16 +130,20 @@ function openConnection( const category = getRequestCategory(description, request); const subscription = new AutoupdateSubscription(streamId, queryParams, requestHash, request, description, [ctx]); - subscriptionQueues[category].push(subscription); - - clearTimeout(openTimeouts[category]); - openTimeouts[category] = setTimeout(() => { - const queue = subscriptionQueues[category]; - subscriptionQueues[category] = []; - openTimeouts[category] = undefined; - - autoupdatePool.openNewStream(queue, queryParams); - }, 5); + if (category) { + subscriptionQueues[category].push(subscription); + + clearTimeout(openTimeouts[category]); + openTimeouts[category] = setTimeout(() => { + const queue = subscriptionQueues[category]; + subscriptionQueues[category] = []; + openTimeouts[category] = undefined; + + autoupdatePool.openNewStream(queue, queryParams); + }, 5); + } else { + autoupdatePool.openNewStream([subscription], queryParams); + } } function closeConnection(ctx: MessagePort, params: AutoupdateCloseStreamParams): void {