Replace recommendation on client and server for motion slide
This commit is contained in:
parent
4fedae63a8
commit
ed4b1c80f1
41
client/src/app/slides/motions/base/base-motion-slide.ts
Normal file
41
client/src/app/slides/motions/base/base-motion-slide.ts
Normal 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>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
import { ReferencedMotions } from '../base/base-motion-slide';
|
||||||
|
|
||||||
export interface MotionTitleInformation {
|
export interface MotionTitleInformation {
|
||||||
title: string;
|
title: string;
|
||||||
identifier?: string;
|
identifier?: string;
|
||||||
@ -14,5 +16,5 @@ export interface MotionBlockSlideMotionRepresentation extends MotionTitleInforma
|
|||||||
export interface MotionBlockSlideData {
|
export interface MotionBlockSlideData {
|
||||||
title: string;
|
title: string;
|
||||||
motions: MotionBlockSlideMotionRepresentation[];
|
motions: MotionBlockSlideMotionRepresentation[];
|
||||||
referenced_motions: { [id: number]: MotionTitleInformation };
|
referenced_motions: ReferencedMotions;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
|
||||||
import {
|
import {
|
||||||
MotionBlockSlideData,
|
MotionBlockSlideData,
|
||||||
MotionBlockSlideMotionRepresentation,
|
MotionBlockSlideMotionRepresentation,
|
||||||
@ -9,15 +8,16 @@ import {
|
|||||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||||
import { StateCssClassMapping } from 'app/site/motions/models/view-workflow';
|
import { StateCssClassMapping } from 'app/site/motions/models/view-workflow';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { BaseMotionSlideComponent } from '../base/base-motion-slide';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'os-motion-block-slide',
|
selector: 'os-motion-block-slide',
|
||||||
templateUrl: './motion-block-slide.component.html',
|
templateUrl: './motion-block-slide.component.html',
|
||||||
styleUrls: ['./motion-block-slide.component.scss']
|
styleUrls: ['./motion-block-slide.component.scss']
|
||||||
})
|
})
|
||||||
export class MotionBlockSlideComponent extends BaseSlideComponent<MotionBlockSlideData> {
|
export class MotionBlockSlideComponent extends BaseMotionSlideComponent<MotionBlockSlideData> {
|
||||||
public constructor(private motionRepo: MotionRepositoryService, private translate: TranslateService) {
|
public constructor(translate: TranslateService, motionRepo: MotionRepositoryService) {
|
||||||
super();
|
super(translate, motionRepo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMotionTitle(motion: MotionTitleInformation): string {
|
public getMotionTitle(motion: MotionTitleInformation): string {
|
||||||
@ -31,16 +31,8 @@ export class MotionBlockSlideComponent extends BaseSlideComponent<MotionBlockSli
|
|||||||
public getRecommendationLabel(motion: MotionBlockSlideMotionRepresentation): string {
|
public getRecommendationLabel(motion: MotionBlockSlideMotionRepresentation): string {
|
||||||
let recommendation = this.translate.instant(motion.recommendation.name);
|
let recommendation = this.translate.instant(motion.recommendation.name);
|
||||||
if (motion.recommendation_extension) {
|
if (motion.recommendation_extension) {
|
||||||
const extension = motion.recommendation_extension.replace(/\[motion:(\d+)\]/g, (match, id) => {
|
recommendation +=
|
||||||
const titleInformation = this.data.data.referenced_motions[id];
|
' ' + this.replaceReferencedMotions(motion.recommendation_extension, this.data.data.referenced_motions);
|
||||||
if (titleInformation) {
|
|
||||||
return this.motionRepo.getIdentifierOrTitle(titleInformation);
|
|
||||||
} else {
|
|
||||||
return this.translate.instant('<unknown motion>');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
recommendation += ' ' + extension;
|
|
||||||
}
|
}
|
||||||
return recommendation;
|
return recommendation;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { ChangeRecoMode, LineNumberingMode } from '../../../site/motions/models/view-motion';
|
import { ChangeRecoMode, LineNumberingMode } from '../../../site/motions/models/view-motion';
|
||||||
import { MergeAmendment } from '../../../shared/models/motions/workflow-state';
|
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.
|
* This interface describes the data returned by the server about an amendment.
|
||||||
@ -65,6 +66,7 @@ export interface MotionSlideData {
|
|||||||
recommender?: string;
|
recommender?: string;
|
||||||
recommendation?: string;
|
recommendation?: string;
|
||||||
recommendation_extension?: string;
|
recommendation_extension?: string;
|
||||||
|
referenced_motions?: ReferencedMotions;
|
||||||
base_motion?: MotionSlideDataBaseMotion;
|
base_motion?: MotionSlideDataBaseMotion;
|
||||||
base_statute?: MotionSlideDataBaseStatute;
|
base_statute?: MotionSlideDataBaseStatute;
|
||||||
amendment_paragraphs: string[];
|
amendment_paragraphs: string[];
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<!-- Recommendation -->
|
<!-- Recommendation -->
|
||||||
<div *ngIf="data.data.recommendation && data.data.recommender">
|
<div *ngIf="data.data.recommendation && data.data.recommender">
|
||||||
<h3>{{ data.data.recommender }}</h3>
|
<h3>{{ data.data.recommender }}</h3>
|
||||||
{{ data.data.recommendation | translate }} {{ data.data.recommendation_extension }}
|
{{ getRecommendationLabel() }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
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 { MotionSlideData, MotionSlideDataAmendment } from './motion-slide-data';
|
||||||
import { ChangeRecoMode, LineNumberingMode } from '../../../site/motions/models/view-motion';
|
import { ChangeRecoMode, LineNumberingMode } from '../../../site/motions/models/view-motion';
|
||||||
import { DiffLinesInParagraph, DiffService, LineRange } from '../../../core/ui-services/diff.service';
|
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 { MotionSlideObjChangeReco } from './motion-slide-obj-change-reco';
|
||||||
import { SlideData } from '../../../core/core-services/projector-data.service';
|
import { SlideData } from '../../../core/core-services/projector-data.service';
|
||||||
import { MotionSlideObjAmendmentParagraph } from './motion-slide-obj-amendment-paragraph';
|
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({
|
@Component({
|
||||||
selector: 'os-motion-slide',
|
selector: 'os-motion-slide',
|
||||||
templateUrl: './motion-slide.component.html',
|
templateUrl: './motion-slide.component.html',
|
||||||
styleUrls: ['./motion-slide.component.scss']
|
styleUrls: ['./motion-slide.component.scss']
|
||||||
})
|
})
|
||||||
export class MotionSlideComponent extends BaseSlideComponent<MotionSlideData> {
|
export class MotionSlideComponent extends BaseMotionSlideComponent<MotionSlideData> {
|
||||||
/**
|
/**
|
||||||
* Indicates the LineNumberingMode Mode.
|
* Indicates the LineNumberingMode Mode.
|
||||||
*/
|
*/
|
||||||
@ -67,11 +70,26 @@ export class MotionSlideComponent extends BaseSlideComponent<MotionSlideData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
|
translate: TranslateService,
|
||||||
|
motionRepo: MotionRepositoryService,
|
||||||
private sanitizer: DomSanitizer,
|
private sanitizer: DomSanitizer,
|
||||||
private lineNumbering: LinenumberingService,
|
private lineNumbering: LinenumberingService,
|
||||||
private diff: DiffService
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
# 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
|
# 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
|
# 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"]}
|
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(
|
def motion_slide(
|
||||||
all_data: AllData, element: Dict[str, Any], projector_id: int
|
all_data: AllData, element: Dict[str, Any], projector_id: int
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
@ -189,9 +213,14 @@ def motion_slide(
|
|||||||
"recommendation_label"
|
"recommendation_label"
|
||||||
]
|
]
|
||||||
if recommendation_state["show_recommendation_extension_field"]:
|
if recommendation_state["show_recommendation_extension_field"]:
|
||||||
return_value["recommendation_extension"] = motion[
|
recommendation_extension = motion["recommendation_extension"]
|
||||||
"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(
|
return_value["recommender"] = get_config(
|
||||||
all_data, "motions_recommendations_by"
|
all_data, "motions_recommendations_by"
|
||||||
@ -228,12 +257,8 @@ def motion_block_slide(
|
|||||||
# All motions in this motion block
|
# All motions in this motion block
|
||||||
motions = []
|
motions = []
|
||||||
|
|
||||||
# All motions meantioned in recommendations of the above motions.
|
# All title information for referenced motions in the recommendation
|
||||||
# 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
|
|
||||||
referenced_motions: Dict[int, Dict[str, str]] = {}
|
referenced_motions: Dict[int, Dict[str, str]] = {}
|
||||||
motion_placeholder_regex = re.compile(r"\[motion:(\d+)\]")
|
|
||||||
|
|
||||||
# Search motions.
|
# Search motions.
|
||||||
for motion in all_data["motions/motion"].values():
|
for motion in all_data["motions/motion"].values():
|
||||||
@ -254,26 +279,10 @@ def motion_block_slide(
|
|||||||
}
|
}
|
||||||
if recommendation["show_recommendation_extension_field"]:
|
if recommendation["show_recommendation_extension_field"]:
|
||||||
recommendation_extension = motion["recommendation_extension"]
|
recommendation_extension = motion["recommendation_extension"]
|
||||||
|
extend_reference_motion_dict(
|
||||||
|
all_data, recommendation_extension, referenced_motions
|
||||||
|
)
|
||||||
motion_object["recommendation_extension"] = recommendation_extension
|
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)
|
motions.append(motion_object)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user