Merge pull request #4920 from emanuelschuetze/configDefaults

Rework config defaults.
This commit is contained in:
Emanuel Schütze 2019-08-21 13:48:55 +02:00 committed by GitHub
commit d3c56efdc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 227 additions and 234 deletions

View File

@ -100,9 +100,6 @@ _('Topics');
_('General'); _('General');
_('Workflow of new motions'); _('Workflow of new motions');
_('Workflow of new statute amendments'); _('Workflow of new statute amendments');
_('Numbered per category');
_('Serially numbered');
_('Set it manually');
_('Motion preamble'); _('Motion preamble');
_('The assembly may decide:'); _('The assembly may decide:');
_('Default line numbering'); _('Default line numbering');
@ -113,8 +110,9 @@ _('Reason required for creating new motion');
_('Hide reason on projector'); _('Hide reason on projector');
_('Hide meta information box on projector'); _('Hide meta information box on projector');
_('Hide recommendation on projector'); _('Hide recommendation on projector');
_('Show the sequential number for a motion');
_('In motion list, motion detail and PDF.');
_('Stop submitting new motions by non-staff users'); _('Stop submitting new motions by non-staff users');
_('Allow to disable versioning');
_('Name of recommender'); _('Name of recommender');
_( _(
'Will be displayed as label before selected recommendation. Use an empty value to disable the recommendation system.' 'Will be displayed as label before selected recommendation. Use an empty value to disable the recommendation system.'
@ -122,7 +120,15 @@ _(
_('Name of recommender for statute amendments'); _('Name of recommender for statute amendments');
_('Will be displayed as label before selected recommendation in statute amendments.'); _('Will be displayed as label before selected recommendation in statute amendments.');
_('Default text version for change recommendations'); _('Default text version for change recommendations');
_('Show the sequential number for a motion'); _('Sort motions by');
// subgroup Numbering
_('Numbered per category');
_('Serially numbered');
_('Set it manually');
_('Number of minimal digits for identifier');
_('Uses leading zeros to sort motions correctly by identifier.');
_('Allow blank in identifier');
_("Blank between prefix and number, e.g. 'A 001'.");
// subgroup Amendments // subgroup Amendments
_('Amendments'); _('Amendments');
_('Activate statute amendments'); _('Activate statute amendments');
@ -135,6 +141,7 @@ _('How to create new amendments');
_('Empty text field'); _('Empty text field');
_('Edit the whole motion text'); _('Edit the whole motion text');
_('Paragraph-based, Diff-enabled'); _('Paragraph-based, Diff-enabled');
_('Allow amendments of amendments');
// subgroup Supporters // subgroup Supporters
_('Supporters'); _('Supporters');
_('Number of (minimum) required supporters for a motion'); _('Number of (minimum) required supporters for a motion');
@ -165,7 +172,6 @@ _('Title for PDF documents of motions');
_('Preamble text for PDF documents of motions'); _('Preamble text for PDF documents of motions');
_('Show submitters and recommendation in table of contents'); _('Show submitters and recommendation in table of contents');
_('Show checkbox to record decision'); _('Show checkbox to record decision');
_('Sort motions by');
// misc motion strings // misc motion strings
_('Amendment'); _('Amendment');
_('Statute amendment for'); _('Statute amendment for');
@ -340,7 +346,7 @@ _('Sender name');
_('The sender address is defined in the OpenSlides server settings and should modified by administrator only.'); _('The sender address is defined in the OpenSlides server settings and should modified by administrator only.');
_('Reply address'); _('Reply address');
_('Email subject'); _('Email subject');
_('Your login for {event_name}'); _('OpenSlides access data');
_('You can use {event_name} and {username} as placeholder.'); _('You can use {event_name} and {username} as placeholder.');
_('Email body'); _('Email body');
_( _(

View File

@ -14,7 +14,6 @@
<!-- required for all kinds of input --> <!-- required for all kinds of input -->
<mat-label>{{ configItem.label | translate }}</mat-label> <mat-label>{{ configItem.label | translate }}</mat-label>
<mat-hint *ngIf="configItem.helpText">{{ configItem.helpText | translate }}</mat-hint>
<span matSuffix> <span matSuffix>
<mat-icon pull="right" class="text-success" *ngIf="updateSuccessIcon">check_circle</mat-icon> <mat-icon pull="right" class="text-success" *ngIf="updateSuccessIcon">check_circle</mat-icon>
</span> </span>
@ -44,9 +43,6 @@
<div class="config-form-group" *ngIf="isExcludedType(configItem.inputType)"> <div class="config-form-group" *ngIf="isExcludedType(configItem.inputType)">
<div *ngIf="configItem.inputType === 'boolean'"> <div *ngIf="configItem.inputType === 'boolean'">
<mat-checkbox formControlName="value">{{ configItem.label | translate }}</mat-checkbox> <mat-checkbox formControlName="value">{{ configItem.label | translate }}</mat-checkbox>
<mat-hint class="hint" *ngIf="configItem.helpText && !error">
{{ configItem.helpText | translate }}
</mat-hint>
<div class="error" *ngIf="error">{{ error }}</div> <div class="error" *ngIf="error">{{ error }}</div>
</div> </div>
@ -60,9 +56,6 @@
placeholder="{{ configItem.label | translate }}" placeholder="{{ configItem.label | translate }}"
[value]="translatedValue" [value]="translatedValue"
></textarea> ></textarea>
<mat-hint class="hint" *ngIf="configItem.helpText && !error">
{{ configItem.helpText | translate }}
</mat-hint>
<span matSuffix> <span matSuffix>
<mat-icon pull="right" class="text-success" *ngIf="updateSuccessIcon"> <mat-icon pull="right" class="text-success" *ngIf="updateSuccessIcon">
check_circle check_circle
@ -79,7 +72,6 @@
/> />
<mat-label>{{ configItem.label | translate }}</mat-label> <mat-label>{{ configItem.label | translate }}</mat-label>
<mat-hint *ngIf="configItem.helpText">{{ configItem.helpText | translate }}</mat-hint>
<span matSuffix> <span matSuffix>
<mat-icon pull="right" class="text-success" *ngIf="updateSuccessIcon">check_circle</mat-icon> <mat-icon pull="right" class="text-success" *ngIf="updateSuccessIcon">check_circle</mat-icon>
</span> </span>
@ -105,6 +97,11 @@
</div> </div>
</form> </form>
</div> </div>
<div class="reset-button">
<button mat-icon-button *ngIf="configItem.helpText" matTooltip="{{ configItem.helpText | translate }}">
<mat-icon>help_outline</mat-icon>
</button>
</div>
<div class="reset-button"> <div class="reset-button">
<button mat-icon-button *ngIf="hasDefault()" matTooltip="{{ 'Reset' | translate }}" (click)="onResetButton()"> <button mat-icon-button *ngIf="hasDefault()" matTooltip="{{ 'Reset' | translate }}" (click)="onResetButton()">
<mat-icon>replay</mat-icon> <mat-icon>replay</mat-icon>

View File

@ -1,14 +1,9 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ConstantsService } from 'app/core/core-services/constants.service';
import { OperatorService } from 'app/core/core-services/operator.service'; import { OperatorService } from 'app/core/core-services/operator.service';
import { ConfigService } from 'app/core/ui-services/config.service'; import { ConfigService } from 'app/core/ui-services/config.service';
import { ViewMotion } from '../models/view-motion'; import { ViewMotion } from '../models/view-motion';
interface Settings {
MOTIONS_ALLOW_AMENDMENTS_OF_AMENDMENTS: boolean;
}
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
@ -17,11 +12,7 @@ export class LocalPermissionsService {
private amendmentEnabled: boolean; private amendmentEnabled: boolean;
private amendmentOfAmendment: boolean; private amendmentOfAmendment: boolean;
public constructor( public constructor(private operator: OperatorService, private configService: ConfigService) {
private operator: OperatorService,
private configService: ConfigService,
private constants: ConstantsService
) {
// load config variables // load config variables
this.configService this.configService
.get<number>('motions_min_supporters') .get<number>('motions_min_supporters')
@ -29,9 +20,9 @@ export class LocalPermissionsService {
this.configService this.configService
.get<boolean>('motions_amendments_enabled') .get<boolean>('motions_amendments_enabled')
.subscribe(enabled => (this.amendmentEnabled = enabled)); .subscribe(enabled => (this.amendmentEnabled = enabled));
this.constants this.configService
.get<Settings>('Settings') .get<boolean>('motions_amendments_of_amendments')
.subscribe(settings => (this.amendmentOfAmendment = settings.MOTIONS_ALLOW_AMENDMENTS_OF_AMENDMENTS)); .subscribe(enabled => (this.amendmentOfAmendment = enabled));
} }
/** /**

View File

@ -9,14 +9,30 @@ def get_config_variables():
It has to be evaluated during app loading (see apps.py). It has to be evaluated during app loading (see apps.py).
""" """
# General
yield ConfigVariable(
name="agenda_start_event_date_time",
default_value=None,
input_type="datetimepicker",
label="Begin of event",
help_text="Input format: DD.MM.YYYY HH:MM",
weight=200,
group="Agenda",
subgroup="General",
)
# Numbering
yield ConfigVariable( yield ConfigVariable(
name="agenda_enable_numbering", name="agenda_enable_numbering",
label="Enable numbering for agenda items", label="Enable numbering for agenda items",
input_type="boolean", input_type="boolean",
default_value=True, default_value=True,
weight=200, weight=205,
group="Agenda", group="Agenda",
subgroup="General", subgroup="Numbering",
) )
yield ConfigVariable( yield ConfigVariable(
@ -24,28 +40,12 @@ def get_config_variables():
default_value="", default_value="",
label="Numbering prefix for agenda items", label="Numbering prefix for agenda items",
help_text="This prefix will be set if you run the automatic agenda numbering.", help_text="This prefix will be set if you run the automatic agenda numbering.",
weight=210, weight=206,
group="Agenda", group="Agenda",
subgroup="General", subgroup="Numbering",
validators=(MaxLengthValidator(20),), validators=(MaxLengthValidator(20),),
) )
yield ConfigVariable(
name="agenda_item_creation",
label="Add to agenda",
default_value="always",
input_type="choice",
choices=(
{"value": "always", "display_name": "Always"},
{"value": "never", "display_name": "Never"},
{"value": "default_yes", "display_name": "Ask, default yes"},
{"value": "default_no", "display_name": "Ask, default no"},
),
weight=212,
group="Agenda",
subgroup="General",
)
yield ConfigVariable( yield ConfigVariable(
name="agenda_numeral_system", name="agenda_numeral_system",
default_value="arabic", default_value="arabic",
@ -55,30 +55,27 @@ def get_config_variables():
{"value": "arabic", "display_name": "Arabic"}, {"value": "arabic", "display_name": "Arabic"},
{"value": "roman", "display_name": "Roman"}, {"value": "roman", "display_name": "Roman"},
), ),
weight=215, weight=207,
group="Agenda", group="Agenda",
subgroup="General", subgroup="Numbering",
) )
yield ConfigVariable( # Visibility
name="agenda_start_event_date_time",
default_value=None,
input_type="datetimepicker",
label="Begin of event",
help_text="Input format: DD.MM.YYYY HH:MM",
weight=220,
group="Agenda",
subgroup="General",
)
yield ConfigVariable( yield ConfigVariable(
name="agenda_hide_internal_items_on_projector", name="agenda_item_creation",
default_value=True, label="Add to agenda",
input_type="boolean", default_value="default_yes",
label="Hide internal items when projecting subitems", input_type="choice",
weight=225, choices=(
{"value": "always", "display_name": "Always"},
{"value": "never", "display_name": "Never"},
{"value": "default_yes", "display_name": "Ask, default yes"},
{"value": "default_no", "display_name": "Ask, default no"},
),
weight=210,
group="Agenda", group="Agenda",
subgroup="General", subgroup="Visibility",
) )
yield ConfigVariable( yield ConfigVariable(
@ -91,19 +88,29 @@ def get_config_variables():
{"value": "3", "display_name": "Hidden item"}, {"value": "3", "display_name": "Hidden item"},
), ),
label="Default visibility for new agenda items (except topics)", label="Default visibility for new agenda items (except topics)",
weight=227, weight=211,
group="Agenda", group="Agenda",
subgroup="General", subgroup="Visibility",
)
yield ConfigVariable(
name="agenda_hide_internal_items_on_projector",
default_value=True,
input_type="boolean",
label="Hide internal items when projecting subitems",
weight=212,
group="Agenda",
subgroup="Visibility",
) )
# List of speakers # List of speakers
yield ConfigVariable( yield ConfigVariable(
name="agenda_show_last_speakers", name="agenda_show_last_speakers",
default_value=1, default_value=0,
input_type="integer", input_type="integer",
label="Number of last speakers to be shown on the projector", label="Number of last speakers to be shown on the projector",
weight=230, weight=220,
group="Agenda", group="Agenda",
subgroup="List of speakers", subgroup="List of speakers",
validators=(MinValueValidator(0),), validators=(MinValueValidator(0),),
@ -115,29 +122,39 @@ def get_config_variables():
input_type="integer", input_type="integer",
label="Show orange countdown in the last x seconds of speaking time", label="Show orange countdown in the last x seconds of speaking time",
help_text="Enter duration in seconds. Choose 0 to disable warning color.", help_text="Enter duration in seconds. Choose 0 to disable warning color.",
weight=235, weight=221,
group="Agenda", group="Agenda",
subgroup="List of speakers", subgroup="List of speakers",
validators=(MinValueValidator(0),), validators=(MinValueValidator(0),),
) )
yield ConfigVariable(
name="projector_default_countdown",
default_value=60,
input_type="integer",
label="Predefined seconds of new countdowns",
weight=222,
group="Agenda",
subgroup="List of speakers",
)
yield ConfigVariable(
name="agenda_couple_countdown_and_speakers",
default_value=True,
input_type="boolean",
label="Couple countdown with the list of speakers",
help_text="[Begin speech] starts the countdown, [End speech] stops the countdown.",
weight=223,
group="Agenda",
subgroup="List of speakers",
)
yield ConfigVariable( yield ConfigVariable(
name="agenda_hide_amount_of_speakers", name="agenda_hide_amount_of_speakers",
default_value=False, default_value=False,
input_type="boolean", input_type="boolean",
label="Hide the amount of speakers in subtitle of list of speakers slide", label="Hide the amount of speakers in subtitle of list of speakers slide",
weight=236, weight=224,
group="Agenda",
subgroup="List of speakers",
)
yield ConfigVariable(
name="agenda_couple_countdown_and_speakers",
default_value=False,
input_type="boolean",
label="Couple countdown with the list of speakers",
help_text="[Begin speech] starts the countdown, [End speech] stops the countdown.",
weight=240,
group="Agenda", group="Agenda",
subgroup="List of speakers", subgroup="List of speakers",
) )
@ -147,7 +164,7 @@ def get_config_variables():
default_value=False, default_value=False,
input_type="boolean", input_type="boolean",
label="Only present participants can be added to the list of speakers", label="Only present participants can be added to the list of speakers",
weight=250, weight=225,
group="Agenda", group="Agenda",
subgroup="List of speakers", subgroup="List of speakers",
) )

View File

@ -67,16 +67,6 @@ def get_config_variables():
subgroup="Ballot and ballot papers", subgroup="Ballot and ballot papers",
) )
yield ConfigVariable(
name="assignments_add_candidates_to_list_of_speakers",
default_value=True,
input_type="boolean",
label="Put all candidates on the list of speakers",
weight=428,
group="Elections",
subgroup="Ballot and ballot papers",
)
yield ConfigVariable( yield ConfigVariable(
name="assignments_pdf_ballot_papers_selection", name="assignments_pdf_ballot_papers_selection",
default_value="CUSTOM_NUMBER", default_value="CUSTOM_NUMBER",
@ -103,12 +93,22 @@ def get_config_variables():
default_value=8, default_value=8,
input_type="integer", input_type="integer",
label="Custom number of ballot papers", label="Custom number of ballot papers",
weight=440, weight=435,
group="Elections", group="Elections",
subgroup="Ballot and ballot papers", subgroup="Ballot and ballot papers",
validators=(MinValueValidator(1),), validators=(MinValueValidator(1),),
) )
yield ConfigVariable(
name="assignments_add_candidates_to_list_of_speakers",
default_value=True,
input_type="boolean",
label="Put all candidates on the list of speakers",
weight=440,
group="Elections",
subgroup="Ballot and ballot papers",
)
# PDF # PDF
yield ConfigVariable( yield ConfigVariable(
@ -117,7 +117,7 @@ def get_config_variables():
label="Title for PDF document (all elections)", label="Title for PDF document (all elections)",
weight=460, weight=460,
group="Elections", group="Elections",
subgroup="PDF", subgroup="PDF export",
) )
yield ConfigVariable( yield ConfigVariable(
@ -126,5 +126,5 @@ def get_config_variables():
label="Preamble text for PDF document (all elections)", label="Preamble text for PDF document (all elections)",
weight=470, weight=470,
group="Elections", group="Elections",
subgroup="PDF", subgroup="PDF export",
) )

View File

@ -133,9 +133,6 @@ class CoreAppConfig(AppConfig):
# Client settings # Client settings
client_settings_keys = [ client_settings_keys = [
"MOTION_IDENTIFIER_MIN_DIGITS",
"MOTION_IDENTIFIER_WITHOUT_BLANKS",
"MOTIONS_ALLOW_AMENDMENTS_OF_AMENDMENTS",
"PRIORITIZED_GROUP_IDS", "PRIORITIZED_GROUP_IDS",
"PING_INTERVAL", "PING_INTERVAL",
"PING_TIMEOUT", "PING_TIMEOUT",

View File

@ -133,38 +133,6 @@ def get_config_variables():
subgroup="System", subgroup="System",
) )
# Projector
yield ConfigVariable(
name="projector_language",
default_value="browser",
input_type="choice",
label="Projector language",
choices=(
{"value": "browser", "display_name": "Current browser language"},
{"value": "en", "display_name": "English"},
{"value": "de", "display_name": "Deutsch"},
{"value": "fr", "display_name": "Français"},
{"value": "es", "display_name": "Español"},
{"value": "pt", "display_name": "Português"},
{"value": "cs", "display_name": "Čeština"},
{"value": "ru", "display_name": "русский"},
),
weight=150,
group="General",
subgroup="Projector",
)
yield ConfigVariable(
name="projector_default_countdown",
default_value=60,
input_type="integer",
label="Predefined seconds of new countdowns",
weight=152,
group="General",
subgroup="Projector",
)
# General export settings # General export settings
yield ConfigVariable( yield ConfigVariable(

View File

@ -49,21 +49,6 @@ def get_config_variables():
subgroup="General", subgroup="General",
) )
yield ConfigVariable(
name="motions_identifier",
default_value="per_category",
input_type="choice",
label="Identifier",
choices=(
{"value": "per_category", "display_name": "Numbered per category"},
{"value": "serially_numbered", "display_name": "Serially numbered"},
{"value": "manually", "display_name": "Set it manually"},
),
weight=315,
group="Motions",
subgroup="General",
)
yield ConfigVariable( yield ConfigVariable(
name="motions_preamble", name="motions_preamble",
default_value="The assembly may decide:", default_value="The assembly may decide:",
@ -75,7 +60,7 @@ def get_config_variables():
yield ConfigVariable( yield ConfigVariable(
name="motions_default_line_numbering", name="motions_default_line_numbering",
default_value="none", default_value="outside",
input_type="choice", input_type="choice",
label="Default line numbering", label="Default line numbering",
choices=( choices=(
@ -90,7 +75,7 @@ def get_config_variables():
yield ConfigVariable( yield ConfigVariable(
name="motions_line_length", name="motions_line_length",
default_value=90, default_value=85,
input_type="integer", input_type="integer",
label="Line length", label="Line length",
help_text="The maximum number of characters per line. Relevant when line numbering is enabled. Min: 40", help_text="The maximum number of characters per line. Relevant when line numbering is enabled. Min: 40",
@ -140,6 +125,17 @@ def get_config_variables():
subgroup="General", subgroup="General",
) )
yield ConfigVariable(
name="motions_show_sequential_numbers",
default_value=True,
input_type="boolean",
label="Show the sequential number for a motion",
help_text="In motion list, motion detail and PDF.",
weight=328,
group="Motions",
subgroup="General",
)
yield ConfigVariable( yield ConfigVariable(
name="motions_recommendations_by", name="motions_recommendations_by",
default_value="", default_value="",
@ -162,7 +158,7 @@ def get_config_variables():
yield ConfigVariable( yield ConfigVariable(
name="motions_recommendation_text_mode", name="motions_recommendation_text_mode",
default_value="original", default_value="diff",
input_type="choice", input_type="choice",
label="Default text version for change recommendations", label="Default text version for change recommendations",
choices=( choices=(
@ -190,14 +186,43 @@ def get_config_variables():
subgroup="General", subgroup="General",
) )
# Numbering
yield ConfigVariable( yield ConfigVariable(
name="motions_show_sequential_numbers", name="motions_identifier",
default_value=True, default_value="per_category",
input_type="boolean", input_type="choice",
label="Show the sequential number for a motion", label="Identifier",
weight=336, choices=(
{"value": "per_category", "display_name": "Numbered per category"},
{"value": "serially_numbered", "display_name": "Serially numbered"},
{"value": "manually", "display_name": "Set it manually"},
),
weight=340,
group="Motions", group="Motions",
subgroup="General", subgroup="Numbering",
)
yield ConfigVariable(
name="motions_identifier_min_digits",
default_value=1,
input_type="integer",
label="Number of minimal digits for identifier",
help_text="Uses leading zeros to sort motions correctly by identifier.",
weight=342,
group="Motions",
subgroup="Numbering",
validators=(MinValueValidator(1),),
)
yield ConfigVariable(
name="motions_identifier_with_blank",
default_value=False,
input_type="boolean",
label="Allow blank in identifier",
help_text="Blank between prefix and number, e.g. 'A 001'.",
weight=344,
group="Motions",
subgroup="Numbering",
) )
# Amendments # Amendments
@ -207,7 +232,7 @@ def get_config_variables():
default_value=False, default_value=False,
input_type="boolean", input_type="boolean",
label="Activate statute amendments", label="Activate statute amendments",
weight=338, weight=350,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
@ -217,17 +242,17 @@ def get_config_variables():
default_value=False, default_value=False,
input_type="boolean", input_type="boolean",
label="Activate amendments", label="Activate amendments",
weight=339, weight=351,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
yield ConfigVariable( yield ConfigVariable(
name="motions_amendments_main_table", name="motions_amendments_main_table",
default_value=False, default_value=True,
input_type="boolean", input_type="boolean",
label="Show amendments together with motions", label="Show amendments together with motions",
weight=340, weight=352,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
@ -236,14 +261,14 @@ def get_config_variables():
name="motions_amendments_prefix", name="motions_amendments_prefix",
default_value="-", default_value="-",
label="Prefix for the identifier for amendments", label="Prefix for the identifier for amendments",
weight=341, weight=353,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
yield ConfigVariable( yield ConfigVariable(
name="motions_amendments_text_mode", name="motions_amendments_text_mode",
default_value="freestyle", default_value="paragraph",
input_type="choice", input_type="choice",
label="How to create new amendments", label="How to create new amendments",
choices=( choices=(
@ -251,17 +276,27 @@ def get_config_variables():
{"value": "fulltext", "display_name": "Edit the whole motion text"}, {"value": "fulltext", "display_name": "Edit the whole motion text"},
{"value": "paragraph", "display_name": "Paragraph-based, Diff-enabled"}, {"value": "paragraph", "display_name": "Paragraph-based, Diff-enabled"},
), ),
weight=342, weight=354,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
yield ConfigVariable( yield ConfigVariable(
name="motions_amendments_multiple_paragraphs", name="motions_amendments_multiple_paragraphs",
default_value=False, default_value=True,
input_type="boolean", input_type="boolean",
label="Amendments can change multiple paragraphs", label="Amendments can change multiple paragraphs",
weight=343, weight=355,
group="Motions",
subgroup="Amendments",
)
yield ConfigVariable(
name="motions_amendments_of_amendments",
default_value=False,
input_type="boolean",
label="Allow amendments of amendments",
weight=356,
group="Motions", group="Motions",
subgroup="Amendments", subgroup="Amendments",
) )
@ -274,7 +309,7 @@ def get_config_variables():
input_type="integer", input_type="integer",
label="Number of (minimum) required supporters for a motion", label="Number of (minimum) required supporters for a motion",
help_text="Choose 0 to disable the supporting system.", help_text="Choose 0 to disable the supporting system.",
weight=345, weight=360,
group="Motions", group="Motions",
subgroup="Supporters", subgroup="Supporters",
validators=(MinValueValidator(0),), validators=(MinValueValidator(0),),
@ -285,7 +320,7 @@ def get_config_variables():
default_value=False, default_value=False,
input_type="boolean", input_type="boolean",
label="Remove all supporters of a motion if a submitter edits his motion in early state", label="Remove all supporters of a motion if a submitter edits his motion in early state",
weight=350, weight=361,
group="Motions", group="Motions",
subgroup="Supporters", subgroup="Supporters",
) )
@ -304,7 +339,7 @@ def get_config_variables():
{"value": "CAST", "display_name": "All casted ballots"}, {"value": "CAST", "display_name": "All casted ballots"},
{"value": "DISABLED", "display_name": "Disabled (no percents)"}, {"value": "DISABLED", "display_name": "Disabled (no percents)"},
), ),
weight=355, weight=370,
group="Motions", group="Motions",
subgroup="Voting and ballot papers", subgroup="Voting and ballot papers",
) )
@ -317,7 +352,7 @@ def get_config_variables():
choices=majorityMethods, choices=majorityMethods,
label="Required majority", label="Required majority",
help_text="Default method to check whether a motion has reached the required majority.", help_text="Default method to check whether a motion has reached the required majority.",
weight=357, weight=372,
group="Motions", group="Motions",
subgroup="Voting and ballot papers", subgroup="Voting and ballot papers",
) )
@ -338,7 +373,7 @@ def get_config_variables():
"display_name": "Use the following custom number", "display_name": "Use the following custom number",
}, },
), ),
weight=360, weight=374,
group="Motions", group="Motions",
subgroup="Voting and ballot papers", subgroup="Voting and ballot papers",
) )
@ -348,7 +383,7 @@ def get_config_variables():
default_value=8, default_value=8,
input_type="integer", input_type="integer",
label="Custom number of ballot papers", label="Custom number of ballot papers",
weight=365, weight=376,
group="Motions", group="Motions",
subgroup="Voting and ballot papers", subgroup="Voting and ballot papers",
validators=(MinValueValidator(1),), validators=(MinValueValidator(1),),
@ -360,7 +395,7 @@ def get_config_variables():
name="motions_export_title", name="motions_export_title",
default_value="Motions", default_value="Motions",
label="Title for PDF documents of motions", label="Title for PDF documents of motions",
weight=370, weight=380,
group="Motions", group="Motions",
subgroup="PDF export", subgroup="PDF export",
) )
@ -369,7 +404,7 @@ def get_config_variables():
name="motions_export_preamble", name="motions_export_preamble",
default_value="", default_value="",
label="Preamble text for PDF documents of motions", label="Preamble text for PDF documents of motions",
weight=375, weight=382,
group="Motions", group="Motions",
subgroup="PDF export", subgroup="PDF export",
) )
@ -379,7 +414,7 @@ def get_config_variables():
default_value=False, default_value=False,
label="Show submitters and recommendation in table of contents", label="Show submitters and recommendation in table of contents",
input_type="boolean", input_type="boolean",
weight=378, weight=384,
group="Motions", group="Motions",
subgroup="PDF export", subgroup="PDF export",
) )
@ -389,7 +424,7 @@ def get_config_variables():
default_value=False, default_value=False,
label="Show checkbox to record decision", label="Show checkbox to record decision",
input_type="boolean", input_type="boolean",
weight=379, weight=386,
group="Motions", group="Motions",
subgroup="PDF export", subgroup="PDF export",
) )

View File

@ -332,26 +332,23 @@ class Motion(RESTModelMixin, AgendaItemWithListOfSpeakersMixin, models.Model):
# Do not set an identifier. # Do not set an identifier.
return return
# If MOTION_IDENTIFIER_WITHOUT_BLANKS is set, don't use blanks when building identifier. # If config 'motions_identifier_with_blank' is set, use blanks when building identifier.
without_blank = ( with_blank = config["motions_identifier_with_blank"]
hasattr(settings, "MOTION_IDENTIFIER_WITHOUT_BLANKS")
and settings.MOTION_IDENTIFIER_WITHOUT_BLANKS
)
# Build prefix. # Build prefix.
if self.is_amendment(): if self.is_amendment():
parent_identifier = self.parent.identifier or "" parent_identifier = self.parent.identifier or ""
if without_blank: if with_blank:
prefix = f"{parent_identifier}{config['motions_amendments_prefix']}" prefix = f"{parent_identifier} {config['motions_amendments_prefix']}"
else: else:
prefix = f"{parent_identifier} {config['motions_amendments_prefix']} " prefix = f"{parent_identifier}{config['motions_amendments_prefix']}"
elif self.category is None or not self.category.prefix: elif self.category is None or not self.category.prefix:
prefix = "" prefix = ""
else: else:
if without_blank: if with_blank:
prefix = self.category.prefix
else:
prefix = f"{self.category.prefix} " prefix = f"{self.category.prefix} "
else:
prefix = self.category.prefix
self._identifier_prefix = prefix self._identifier_prefix = prefix
# Use the already assigned identifier_number, if the motion has one. # Use the already assigned identifier_number, if the motion has one.
@ -402,20 +399,16 @@ class Motion(RESTModelMixin, AgendaItemWithListOfSpeakersMixin, models.Model):
def extend_identifier_number(cls, number): def extend_identifier_number(cls, number):
""" """
Returns the number used in the set_identifier method with leading Returns the number used in the set_identifier method with leading
zero charaters according to the settings value zero charaters according to the config value.
MOTION_IDENTIFIER_MIN_DIGITS.
""" """
result = str(number) result = str(number)
if ( if config["motions_identifier_min_digits"]:
hasattr(settings, "MOTION_IDENTIFIER_MIN_DIGITS") if not isinstance(config["motions_identifier_min_digits"], int):
and settings.MOTION_IDENTIFIER_MIN_DIGITS
):
if not isinstance(settings.MOTION_IDENTIFIER_MIN_DIGITS, int):
raise ImproperlyConfigured( raise ImproperlyConfigured(
"Settings value MOTION_IDENTIFIER_MIN_DIGITS must be an integer." "Config value 'motions_identifier_min_digits' must be an integer."
) )
result = ( result = (
"0" * (settings.MOTION_IDENTIFIER_MIN_DIGITS - len(str(number))) "0" * (config["motions_identifier_min_digits"] - len(str(number)))
+ result + result
) )
return result return result

View File

@ -44,7 +44,7 @@ def get_config_variables():
label="Title for access data and welcome PDF", label="Title for access data and welcome PDF",
weight=520, weight=520,
group="Participants", group="Participants",
subgroup="PDF", subgroup="PDF export",
) )
yield ConfigVariable( yield ConfigVariable(
@ -53,7 +53,7 @@ def get_config_variables():
label="Help text for access data and welcome PDF", label="Help text for access data and welcome PDF",
weight=530, weight=530,
group="Participants", group="Participants",
subgroup="PDF", subgroup="PDF export",
) )
# TODO: Use Django's URLValidator here. # TODO: Use Django's URLValidator here.
@ -64,7 +64,7 @@ def get_config_variables():
help_text="Used for QRCode in PDF of access data.", help_text="Used for QRCode in PDF of access data.",
weight=540, weight=540,
group="Participants", group="Participants",
subgroup="PDF", subgroup="PDF export",
) )
yield ConfigVariable( yield ConfigVariable(
@ -74,7 +74,7 @@ def get_config_variables():
help_text="Used for WLAN QRCode in PDF of access data.", help_text="Used for WLAN QRCode in PDF of access data.",
weight=550, weight=550,
group="Participants", group="Participants",
subgroup="PDF", subgroup="PDF export",
) )
yield ConfigVariable( yield ConfigVariable(
@ -84,7 +84,7 @@ def get_config_variables():
help_text="Used for WLAN QRCode in PDF of access data.", help_text="Used for WLAN QRCode in PDF of access data.",
weight=560, weight=560,
group="Participants", group="Participants",
subgroup="PDF", subgroup="PDF export",
) )
yield ConfigVariable( yield ConfigVariable(
@ -101,7 +101,7 @@ def get_config_variables():
), ),
weight=570, weight=570,
group="Participants", group="Participants",
subgroup="PDF", subgroup="PDF export",
) )
# Email # Email
@ -129,7 +129,7 @@ def get_config_variables():
yield ConfigVariable( yield ConfigVariable(
name="users_email_subject", name="users_email_subject",
default_value="Your login for {event_name}", default_value="OpenSlides access data",
input_type="string", input_type="string",
label="Email subject", label="Email subject",
help_text="You can use {event_name} and {username} as placeholder.", help_text="You can use {event_name} and {username} as placeholder.",

View File

@ -170,10 +170,3 @@ LOGGING = {
} }
}, },
} }
# Customization of OpenSlides apps
MOTION_IDENTIFIER_MIN_DIGITS = 1
MOTION_IDENTIFIER_WITHOUT_BLANKS = False
MOTIONS_ALLOW_AMENDMENTS_OF_AMENDMENTS = True

View File

@ -1,7 +1,6 @@
import json import json
import pytest import pytest
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.urls import reverse from django.urls import reverse
from rest_framework import status from rest_framework import status
@ -295,7 +294,7 @@ class CreateMotion(TestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
motion = Motion.objects.get() motion = Motion.objects.get()
self.assertEqual(motion.category, category) self.assertEqual(motion.category, category)
self.assertEqual(motion.identifier, "TEST_PREFIX_la0eadaewuec3seoxeiN 1") self.assertEqual(motion.identifier, "TEST_PREFIX_la0eadaewuec3seoxeiN1")
def test_with_submitters(self): def test_with_submitters(self):
submitter_1 = get_user_model().objects.create_user( submitter_1 = get_user_model().objects.create_user(
@ -1942,24 +1941,25 @@ class NumberMotionsInCategories(TestCase):
def test_with_blanks(self): def test_with_blanks(self):
config["motions_amendments_prefix"] = "-X" config["motions_amendments_prefix"] = "-X"
settings.MOTION_IDENTIFIER_WITHOUT_BLANKS = True config["motions_identifier_with_blank"] = False
settings.MOTION_IDENTIFIER_MIN_DIGITS = 3 config["motions_identifier_min_digits"] = 3
response = self.client.post(reverse("category-numbering", args=[self.A.pk])) response = self.client.post(reverse("category-numbering", args=[self.A.pk]))
settings.MOTION_IDENTIFIER_WITHOUT_BLANKS = False config["motions_identifier_with_blank"] = True
settings.MOTION_IDENTIFIER_MIN_DIGITS = 1 config["motions_identifier_min_digits"] = 1
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(Motion.objects.get(pk=self.M1.pk).identifier, "test_A001") self.assertEqual(Motion.objects.get(pk=self.M1.pk).identifier, "test_A 001")
self.assertEqual(Motion.objects.get(pk=self.M3.pk).identifier, "test_A002") self.assertEqual(Motion.objects.get(pk=self.M3.pk).identifier, "test_A 002")
self.assertEqual(Motion.objects.get(pk=self.M2.pk).identifier, "test_C003") self.assertEqual(Motion.objects.get(pk=self.M2.pk).identifier, "test_C 003")
self.assertEqual( self.assertEqual(
Motion.objects.get(pk=self.M2_A1.pk).identifier, "test_C003-X002" Motion.objects.get(pk=self.M2_A1.pk).identifier, "test_C 003 -X 002"
) )
self.assertEqual( self.assertEqual(
Motion.objects.get(pk=self.M2_A1_A1.pk).identifier, "test_C003-X002-X001" Motion.objects.get(pk=self.M2_A1_A1.pk).identifier,
"test_C 003 -X 002 -X 001",
) )
self.assertEqual( self.assertEqual(
Motion.objects.get(pk=self.M2_A2.pk).identifier, "test_C003-X001" Motion.objects.get(pk=self.M2_A2.pk).identifier, "test_C 003 -X 001"
) )
def test_existing_identifier_no_category(self): def test_existing_identifier_no_category(self):

View File

@ -89,13 +89,14 @@ class ModelTest(TestCase):
parent + a suffix. parent + a suffix.
""" """
config["motions_amendments_enabled"] = True config["motions_amendments_enabled"] = True
config["motions_identifier_with_blank"] = False
self.motion.identifier = "Parent identifier" self.motion.identifier = "Parent identifier"
self.motion.save() self.motion.save()
motion = Motion(parent=self.motion) motion = Motion(parent=self.motion)
motion.set_identifier() motion.set_identifier()
self.assertEqual(motion.identifier, "Parent identifier - 1") self.assertEqual(motion.identifier, "Parent identifier-1")
def test_set_identifier_second_amendment(self): def test_set_identifier_second_amendment(self):
""" """
@ -110,4 +111,4 @@ class ModelTest(TestCase):
motion.set_identifier() motion.set_identifier()
self.assertEqual(motion.identifier, "Parent identifier - 2") self.assertEqual(motion.identifier, "Parent identifier-2")

View File

@ -60,11 +60,6 @@ STATICFILES_DIRS.insert(0, os.path.join(OPENSLIDES_USER_DATA_PATH, "static")) #
MEDIA_ROOT = os.path.join(OPENSLIDES_USER_DATA_PATH, "") MEDIA_ROOT = os.path.join(OPENSLIDES_USER_DATA_PATH, "")
# Customization of OpenSlides apps
MOTION_IDENTIFIER_MIN_DIGITS = 1
# Special settings only for testing # Special settings only for testing
# Use a faster password hasher. # Use a faster password hasher.

View File

@ -295,8 +295,8 @@ async def test_motion_slide(all_data):
"show_meta_box": True, "show_meta_box": True,
"reason": "", "reason": "",
"submitter": ["Administrator"], "submitter": ["Administrator"],
"line_length": 90, "line_length": 85,
"line_numbering_mode": "none", "line_numbering_mode": "outside",
"preamble": "The assembly may decide:", "preamble": "The assembly may decide:",
"recommendation_referencing_motions": None, "recommendation_referencing_motions": None,
} }
@ -321,8 +321,8 @@ async def test_amendment_slide(all_data):
"show_meta_box": True, "show_meta_box": True,
"reason": "", "reason": "",
"submitter": ["Administrator"], "submitter": ["Administrator"],
"line_length": 90, "line_length": 85,
"line_numbering_mode": "none", "line_numbering_mode": "outside",
"preamble": "The assembly may decide:", "preamble": "The assembly may decide:",
"recommendation_referencing_motions": None, "recommendation_referencing_motions": None,
} }
@ -347,8 +347,8 @@ async def test_statute_amendment_slide(all_data):
"show_meta_box": True, "show_meta_box": True,
"reason": "", "reason": "",
"submitter": ["Administrator"], "submitter": ["Administrator"],
"line_length": 90, "line_length": 85,
"line_numbering_mode": "none", "line_numbering_mode": "outside",
"preamble": "The assembly may decide:", "preamble": "The assembly may decide:",
"recommendation_referencing_motions": None, "recommendation_referencing_motions": None,
} }