Replace recommendation on client and server for motion slide

This commit is contained in:
FinnStutzenstein 2019-03-06 16:59:18 +01:00
parent 4fedae63a8
commit ed4b1c80f1
7 changed files with 110 additions and 46 deletions

View File

@ -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:<id>]`) in strings.
*/
export class BaseMotionSlideComponent<T extends object> extends BaseSlideComponent<T> {
public constructor(protected translate: TranslateService, protected motionRepo: MotionRepositoryService) {
super();
}
/**
* Replaces all motion placeholders with the motion titles or `<unknown motion>` 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('<unknown motion>');
}
});
}
}

View File

@ -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;
}

View File

@ -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<MotionBlockSlideData> {
public constructor(private motionRepo: MotionRepositoryService, private translate: TranslateService) {
super();
export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBlockSlideData> {
public constructor(translate: TranslateService, motionRepo: MotionRepositoryService) {
super(translate, motionRepo);
}
public getMotionTitle(motion: MotionTitleInformation): string {
@ -31,16 +31,8 @@ export class MotionBlockSlideComponent extends BaseSlideComponent<MotionBlockSli
public getRecommendationLabel(motion: MotionBlockSlideMotionRepresentation): string {
let recommendation = this.translate.instant(motion.recommendation.name);
if (motion.recommendation_extension) {
const extension = motion.recommendation_extension.replace(/\[motion:(\d+)\]/g, (match, id) => {
const titleInformation = this.data.data.referenced_motions[id];
if (titleInformation) {
return this.motionRepo.getIdentifierOrTitle(titleInformation);
} else {
return this.translate.instant('<unknown motion>');
}
});
recommendation += ' ' + extension;
recommendation +=
' ' + this.replaceReferencedMotions(motion.recommendation_extension, this.data.data.referenced_motions);
}
return recommendation;
}

View File

@ -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[];

View File

@ -9,7 +9,7 @@
<!-- Recommendation -->
<div *ngIf="data.data.recommendation && data.data.recommender">
<h3>{{ data.data.recommender }}</h3>
{{ data.data.recommendation | translate }} {{ data.data.recommendation_extension }}
{{ getRecommendationLabel() }}
</div>
</div>

View File

@ -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<MotionSlideData> {
export class MotionSlideComponent extends BaseMotionSlideComponent<MotionSlideData> {
/**
* Indicates the LineNumberingMode Mode.
*/
@ -67,11 +70,26 @@ export class MotionSlideComponent extends BaseSlideComponent<MotionSlideData> {
}
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;
}
/**

View File

@ -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:<id>]
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:<id>]
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)