From ed4b1c80f1d5bec57dd509fb8f83568ebd421da1 Mon Sep 17 00:00:00 2001 From: FinnStutzenstein Date: Wed, 6 Mar 2019 16:59:18 +0100 Subject: [PATCH] Replace recommendation on client and server for motion slide --- .../slides/motions/base/base-motion-slide.ts | 41 ++++++++++++ .../motion-block/motion-block-slide-data.ts | 4 +- .../motion-block-slide.component.ts | 20 ++---- .../motions/motion/motion-slide-data.ts | 2 + .../motion/motion-slide.component.html | 2 +- .../motions/motion/motion-slide.component.ts | 24 ++++++- openslides/motions/projector.py | 63 +++++++++++-------- 7 files changed, 110 insertions(+), 46 deletions(-) create mode 100644 client/src/app/slides/motions/base/base-motion-slide.ts diff --git a/client/src/app/slides/motions/base/base-motion-slide.ts b/client/src/app/slides/motions/base/base-motion-slide.ts new file mode 100644 index 000000000..e03f61add --- /dev/null +++ b/client/src/app/slides/motions/base/base-motion-slide.ts @@ -0,0 +1,41 @@ +import { TranslateService } from '@ngx-translate/core'; + +import { BaseSlideComponent } from 'app/slides/base-slide-component'; +import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service'; +import { MotionTitleInformation } from '../motion-block/motion-block-slide-data'; + +/** + * Format for referenced motions: A mapping of motion ids to their title information. + */ +export interface ReferencedMotions { + [id: number]: MotionTitleInformation; +} + +/** + * Base slide for motions and motion blocks. This Provides the functionality of + * replacing referenced motions (format: `[motion:]`) in strings. + */ +export class BaseMotionSlideComponent extends BaseSlideComponent { + public constructor(protected translate: TranslateService, protected motionRepo: MotionRepositoryService) { + super(); + } + + /** + * Replaces all motion placeholders with the motion titles or `` if the + * referenced motion doe snot exist. + * + * @param text the text to replace + * @param referencedMotions an object holding the title information for all referenced motions + * @returns the new string + */ + public replaceReferencedMotions(text: string, referencedMotions: ReferencedMotions): string { + return text.replace(/\[motion:(\d+)\]/g, (match, id) => { + const titleInformation = referencedMotions[id]; + if (titleInformation) { + return this.motionRepo.getIdentifierOrTitle(titleInformation); + } else { + return this.translate.instant(''); + } + }); + } +} diff --git a/client/src/app/slides/motions/motion-block/motion-block-slide-data.ts b/client/src/app/slides/motions/motion-block/motion-block-slide-data.ts index 4e91fd0da..98b3e79dd 100644 --- a/client/src/app/slides/motions/motion-block/motion-block-slide-data.ts +++ b/client/src/app/slides/motions/motion-block/motion-block-slide-data.ts @@ -1,3 +1,5 @@ +import { ReferencedMotions } from '../base/base-motion-slide'; + export interface MotionTitleInformation { title: string; identifier?: string; @@ -14,5 +16,5 @@ export interface MotionBlockSlideMotionRepresentation extends MotionTitleInforma export interface MotionBlockSlideData { title: string; motions: MotionBlockSlideMotionRepresentation[]; - referenced_motions: { [id: number]: MotionTitleInformation }; + referenced_motions: ReferencedMotions; } diff --git a/client/src/app/slides/motions/motion-block/motion-block-slide.component.ts b/client/src/app/slides/motions/motion-block/motion-block-slide.component.ts index 0109cb7bf..27013435a 100644 --- a/client/src/app/slides/motions/motion-block/motion-block-slide.component.ts +++ b/client/src/app/slides/motions/motion-block/motion-block-slide.component.ts @@ -1,6 +1,5 @@ import { Component } from '@angular/core'; -import { BaseSlideComponent } from 'app/slides/base-slide-component'; import { MotionBlockSlideData, MotionBlockSlideMotionRepresentation, @@ -9,15 +8,16 @@ import { import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service'; import { StateCssClassMapping } from 'app/site/motions/models/view-workflow'; import { TranslateService } from '@ngx-translate/core'; +import { BaseMotionSlideComponent } from '../base/base-motion-slide'; @Component({ selector: 'os-motion-block-slide', templateUrl: './motion-block-slide.component.html', styleUrls: ['./motion-block-slide.component.scss'] }) -export class MotionBlockSlideComponent extends BaseSlideComponent { - public constructor(private motionRepo: MotionRepositoryService, private translate: TranslateService) { - super(); +export class MotionBlockSlideComponent extends BaseMotionSlideComponent { + public constructor(translate: TranslateService, motionRepo: MotionRepositoryService) { + super(translate, motionRepo); } public getMotionTitle(motion: MotionTitleInformation): string { @@ -31,16 +31,8 @@ export class MotionBlockSlideComponent extends BaseSlideComponent { - const titleInformation = this.data.data.referenced_motions[id]; - if (titleInformation) { - return this.motionRepo.getIdentifierOrTitle(titleInformation); - } else { - return this.translate.instant(''); - } - }); - - recommendation += ' ' + extension; + recommendation += + ' ' + this.replaceReferencedMotions(motion.recommendation_extension, this.data.data.referenced_motions); } return recommendation; } diff --git a/client/src/app/slides/motions/motion/motion-slide-data.ts b/client/src/app/slides/motions/motion/motion-slide-data.ts index f0f50d45e..d1aebe863 100644 --- a/client/src/app/slides/motions/motion/motion-slide-data.ts +++ b/client/src/app/slides/motions/motion/motion-slide-data.ts @@ -1,5 +1,6 @@ import { ChangeRecoMode, LineNumberingMode } from '../../../site/motions/models/view-motion'; import { MergeAmendment } from '../../../shared/models/motions/workflow-state'; +import { ReferencedMotions } from '../base/base-motion-slide'; /** * This interface describes the data returned by the server about an amendment. @@ -65,6 +66,7 @@ export interface MotionSlideData { recommender?: string; recommendation?: string; recommendation_extension?: string; + referenced_motions?: ReferencedMotions; base_motion?: MotionSlideDataBaseMotion; base_statute?: MotionSlideDataBaseStatute; amendment_paragraphs: string[]; diff --git a/client/src/app/slides/motions/motion/motion-slide.component.html b/client/src/app/slides/motions/motion/motion-slide.component.html index ec8e6532d..6d66849a2 100644 --- a/client/src/app/slides/motions/motion/motion-slide.component.html +++ b/client/src/app/slides/motions/motion/motion-slide.component.html @@ -9,7 +9,7 @@

{{ data.data.recommender }}

- {{ data.data.recommendation | translate }} {{ data.data.recommendation_extension }} + {{ getRecommendationLabel() }}
diff --git a/client/src/app/slides/motions/motion/motion-slide.component.ts b/client/src/app/slides/motions/motion/motion-slide.component.ts index 06bb8c4dc..f6c527241 100644 --- a/client/src/app/slides/motions/motion/motion-slide.component.ts +++ b/client/src/app/slides/motions/motion/motion-slide.component.ts @@ -1,7 +1,8 @@ import { Component, Input } from '@angular/core'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; -import { BaseSlideComponent } from 'app/slides/base-slide-component'; +import { TranslateService } from '@ngx-translate/core'; + import { MotionSlideData, MotionSlideDataAmendment } from './motion-slide-data'; import { ChangeRecoMode, LineNumberingMode } from '../../../site/motions/models/view-motion'; import { DiffLinesInParagraph, DiffService, LineRange } from '../../../core/ui-services/diff.service'; @@ -10,13 +11,15 @@ import { ViewUnifiedChange } from '../../../shared/models/motions/view-unified-c import { MotionSlideObjChangeReco } from './motion-slide-obj-change-reco'; import { SlideData } from '../../../core/core-services/projector-data.service'; import { MotionSlideObjAmendmentParagraph } from './motion-slide-obj-amendment-paragraph'; +import { BaseMotionSlideComponent } from '../base/base-motion-slide'; +import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service'; @Component({ selector: 'os-motion-slide', templateUrl: './motion-slide.component.html', styleUrls: ['./motion-slide.component.scss'] }) -export class MotionSlideComponent extends BaseSlideComponent { +export class MotionSlideComponent extends BaseMotionSlideComponent { /** * Indicates the LineNumberingMode Mode. */ @@ -67,11 +70,26 @@ export class MotionSlideComponent extends BaseSlideComponent { } public constructor( + translate: TranslateService, + motionRepo: MotionRepositoryService, private sanitizer: DomSanitizer, private lineNumbering: LinenumberingService, private diff: DiffService ) { - super(); + super(translate, motionRepo); + } + + public getRecommendationLabel(): string { + let recommendation = this.translate.instant(this.data.data.recommendation); + if (this.data.data.recommendation_extension) { + recommendation += + ' ' + + this.replaceReferencedMotions( + this.data.data.recommendation_extension, + this.data.data.referenced_motions + ); + } + return recommendation; } /** diff --git a/openslides/motions/projector.py b/openslides/motions/projector.py index e0d156652..cf067423d 100644 --- a/openslides/motions/projector.py +++ b/openslides/motions/projector.py @@ -10,6 +10,8 @@ from ..utils.projector import ( ) +motion_placeholder_regex = re.compile(r"\[motion:(\d+)\]") + # Important: All functions have to be prune. This means, that thay can only # access the data, that they get as argument and do not have any # side effects. They are called from an async context. So they have @@ -98,6 +100,28 @@ def get_amendment_base_statute(amendment, all_data): return {"title": statute["title"], "text": statute["text"]} +def extend_reference_motion_dict( + all_data: AllData, + recommendation: str, + referenced_motions: Dict[int, Dict[str, str]], +) -> None: + """ + Extends a dict of motion ids mapped to their title information. + The client can replace the placeholders in the recommendation correctly. + """ + # Collect all meantioned motions via [motion:] + referenced_ids = [ + int(id) for id in motion_placeholder_regex.findall(recommendation) + ] + for id in referenced_ids: + # Put every referenced motion into the referenced_motions dict + if id not in referenced_motions and id in all_data["motions/motion"]: + referenced_motions[id] = { + "title": all_data["motions/motion"][id]["title"], + "identifier": all_data["motions/motion"][id]["identifier"], + } + + def motion_slide( all_data: AllData, element: Dict[str, Any], projector_id: int ) -> Dict[str, Any]: @@ -189,9 +213,14 @@ def motion_slide( "recommendation_label" ] if recommendation_state["show_recommendation_extension_field"]: - return_value["recommendation_extension"] = motion[ - "recommendation_extension" - ] + recommendation_extension = motion["recommendation_extension"] + # All title information for referenced motions in the recommendation + referenced_motions: Dict[int, Dict[str, str]] = {} + extend_reference_motion_dict( + all_data, recommendation_extension, referenced_motions + ) + return_value["recommendation_extension"] = recommendation_extension + return_value["referenced_motions"] = referenced_motions return_value["recommender"] = get_config( all_data, "motions_recommendations_by" @@ -228,12 +257,8 @@ def motion_block_slide( # All motions in this motion block motions = [] - # All motions meantioned in recommendations of the above motions. - # Only title_informations will be collected. With this, the client can - # replace the placeholders in the recommendation correctly - # This maps the motion id to the title information + # All title information for referenced motions in the recommendation referenced_motions: Dict[int, Dict[str, str]] = {} - motion_placeholder_regex = re.compile(r"\[motion:(\d+)\]") # Search motions. for motion in all_data["motions/motion"].values(): @@ -254,26 +279,10 @@ def motion_block_slide( } if recommendation["show_recommendation_extension_field"]: recommendation_extension = motion["recommendation_extension"] - + extend_reference_motion_dict( + all_data, recommendation_extension, referenced_motions + ) motion_object["recommendation_extension"] = recommendation_extension - # Collect all meantioned motions via [motion:] - referenced_ids = [ - int(id) - for id in motion_placeholder_regex.findall( - recommendation_extension - ) - ] - for id in referenced_ids: - if ( - id not in referenced_motions - and id in all_data["motions/motion"] - ): - referenced_motions[id] = { - "title": all_data["motions/motion"][id]["title"], - "identifier": all_data["motions/motion"][id][ - "identifier" - ], - } motions.append(motion_object)