Rework config defaults.

- move motion setttings from settings.py to config that user can change
  it while runtime
- show help text for config fields as tooltip
This commit is contained in:
Emanuel Schütze 2019-08-14 21:53:42 +02:00
parent ba5782a655
commit f981106524
15 changed files with 227 additions and 234 deletions

View File

@ -100,9 +100,6 @@ _('Topics');
_('General');
_('Workflow of new motions');
_('Workflow of new statute amendments');
_('Numbered per category');
_('Serially numbered');
_('Set it manually');
_('Motion preamble');
_('The assembly may decide:');
_('Default line numbering');
@ -113,8 +110,9 @@ _('Reason required for creating new motion');
_('Hide reason on projector');
_('Hide meta information box 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');
_('Allow to disable versioning');
_('Name of recommender');
_(
'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');
_('Will be displayed as label before selected recommendation in statute amendments.');
_('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
_('Amendments');
_('Activate statute amendments');
@ -135,6 +141,7 @@ _('How to create new amendments');
_('Empty text field');
_('Edit the whole motion text');
_('Paragraph-based, Diff-enabled');
_('Allow amendments of amendments');
// subgroup Supporters
_('Supporters');
_('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');
_('Show submitters and recommendation in table of contents');
_('Show checkbox to record decision');
_('Sort motions by');
// misc motion strings
_('Amendment');
_('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.');
_('Reply address');
_('Email subject');
_('Your login for {event_name}');
_('OpenSlides access data');
_('You can use {event_name} and {username} as placeholder.');
_('Email body');
_(

View File

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

View File

@ -1,14 +1,9 @@
import { Injectable } from '@angular/core';
import { ConstantsService } from 'app/core/core-services/constants.service';
import { OperatorService } from 'app/core/core-services/operator.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { ViewMotion } from '../models/view-motion';
interface Settings {
MOTIONS_ALLOW_AMENDMENTS_OF_AMENDMENTS: boolean;
}
@Injectable({
providedIn: 'root'
})
@ -17,11 +12,7 @@ export class LocalPermissionsService {
private amendmentEnabled: boolean;
private amendmentOfAmendment: boolean;
public constructor(
private operator: OperatorService,
private configService: ConfigService,
private constants: ConstantsService
) {
public constructor(private operator: OperatorService, private configService: ConfigService) {
// load config variables
this.configService
.get<number>('motions_min_supporters')
@ -29,9 +20,9 @@ export class LocalPermissionsService {
this.configService
.get<boolean>('motions_amendments_enabled')
.subscribe(enabled => (this.amendmentEnabled = enabled));
this.constants
.get<Settings>('Settings')
.subscribe(settings => (this.amendmentOfAmendment = settings.MOTIONS_ALLOW_AMENDMENTS_OF_AMENDMENTS));
this.configService
.get<boolean>('motions_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).
"""
# 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(
name="agenda_enable_numbering",
label="Enable numbering for agenda items",
input_type="boolean",
default_value=True,
weight=200,
weight=205,
group="Agenda",
subgroup="General",
subgroup="Numbering",
)
yield ConfigVariable(
@ -24,28 +40,12 @@ def get_config_variables():
default_value="",
label="Numbering prefix for agenda items",
help_text="This prefix will be set if you run the automatic agenda numbering.",
weight=210,
weight=206,
group="Agenda",
subgroup="General",
subgroup="Numbering",
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(
name="agenda_numeral_system",
default_value="arabic",
@ -55,30 +55,27 @@ def get_config_variables():
{"value": "arabic", "display_name": "Arabic"},
{"value": "roman", "display_name": "Roman"},
),
weight=215,
weight=207,
group="Agenda",
subgroup="General",
subgroup="Numbering",
)
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=220,
group="Agenda",
subgroup="General",
)
# Visibility
yield ConfigVariable(
name="agenda_hide_internal_items_on_projector",
default_value=True,
input_type="boolean",
label="Hide internal items when projecting subitems",
weight=225,
name="agenda_item_creation",
label="Add to agenda",
default_value="default_yes",
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=210,
group="Agenda",
subgroup="General",
subgroup="Visibility",
)
yield ConfigVariable(
@ -91,19 +88,29 @@ def get_config_variables():
{"value": "3", "display_name": "Hidden item"},
),
label="Default visibility for new agenda items (except topics)",
weight=227,
weight=211,
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
yield ConfigVariable(
name="agenda_show_last_speakers",
default_value=1,
default_value=0,
input_type="integer",
label="Number of last speakers to be shown on the projector",
weight=230,
weight=220,
group="Agenda",
subgroup="List of speakers",
validators=(MinValueValidator(0),),
@ -115,29 +122,39 @@ def get_config_variables():
input_type="integer",
label="Show orange countdown in the last x seconds of speaking time",
help_text="Enter duration in seconds. Choose 0 to disable warning color.",
weight=235,
weight=221,
group="Agenda",
subgroup="List of speakers",
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(
name="agenda_hide_amount_of_speakers",
default_value=False,
input_type="boolean",
label="Hide the amount of speakers in subtitle of list of speakers slide",
weight=236,
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,
weight=224,
group="Agenda",
subgroup="List of speakers",
)
@ -147,7 +164,7 @@ def get_config_variables():
default_value=False,
input_type="boolean",
label="Only present participants can be added to the list of speakers",
weight=250,
weight=225,
group="Agenda",
subgroup="List of speakers",
)

View File

@ -67,16 +67,6 @@ def get_config_variables():
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(
name="assignments_pdf_ballot_papers_selection",
default_value="CUSTOM_NUMBER",
@ -103,12 +93,22 @@ def get_config_variables():
default_value=8,
input_type="integer",
label="Custom number of ballot papers",
weight=440,
weight=435,
group="Elections",
subgroup="Ballot and ballot papers",
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
yield ConfigVariable(
@ -117,7 +117,7 @@ def get_config_variables():
label="Title for PDF document (all elections)",
weight=460,
group="Elections",
subgroup="PDF",
subgroup="PDF export",
)
yield ConfigVariable(
@ -126,5 +126,5 @@ def get_config_variables():
label="Preamble text for PDF document (all elections)",
weight=470,
group="Elections",
subgroup="PDF",
subgroup="PDF export",
)

View File

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

View File

@ -133,38 +133,6 @@ def get_config_variables():
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
yield ConfigVariable(

View File

@ -49,21 +49,6 @@ def get_config_variables():
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(
name="motions_preamble",
default_value="The assembly may decide:",
@ -75,7 +60,7 @@ def get_config_variables():
yield ConfigVariable(
name="motions_default_line_numbering",
default_value="none",
default_value="outside",
input_type="choice",
label="Default line numbering",
choices=(
@ -90,7 +75,7 @@ def get_config_variables():
yield ConfigVariable(
name="motions_line_length",
default_value=90,
default_value=85,
input_type="integer",
label="Line length",
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",
)
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(
name="motions_recommendations_by",
default_value="",
@ -162,7 +158,7 @@ def get_config_variables():
yield ConfigVariable(
name="motions_recommendation_text_mode",
default_value="original",
default_value="diff",
input_type="choice",
label="Default text version for change recommendations",
choices=(
@ -190,14 +186,43 @@ def get_config_variables():
subgroup="General",
)
# Numbering
yield ConfigVariable(
name="motions_show_sequential_numbers",
default_value=True,
input_type="boolean",
label="Show the sequential number for a motion",
weight=336,
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=340,
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
@ -207,7 +232,7 @@ def get_config_variables():
default_value=False,
input_type="boolean",
label="Activate statute amendments",
weight=338,
weight=350,
group="Motions",
subgroup="Amendments",
)
@ -217,17 +242,17 @@ def get_config_variables():
default_value=False,
input_type="boolean",
label="Activate amendments",
weight=339,
weight=351,
group="Motions",
subgroup="Amendments",
)
yield ConfigVariable(
name="motions_amendments_main_table",
default_value=False,
default_value=True,
input_type="boolean",
label="Show amendments together with motions",
weight=340,
weight=352,
group="Motions",
subgroup="Amendments",
)
@ -236,14 +261,14 @@ def get_config_variables():
name="motions_amendments_prefix",
default_value="-",
label="Prefix for the identifier for amendments",
weight=341,
weight=353,
group="Motions",
subgroup="Amendments",
)
yield ConfigVariable(
name="motions_amendments_text_mode",
default_value="freestyle",
default_value="paragraph",
input_type="choice",
label="How to create new amendments",
choices=(
@ -251,17 +276,27 @@ def get_config_variables():
{"value": "fulltext", "display_name": "Edit the whole motion text"},
{"value": "paragraph", "display_name": "Paragraph-based, Diff-enabled"},
),
weight=342,
weight=354,
group="Motions",
subgroup="Amendments",
)
yield ConfigVariable(
name="motions_amendments_multiple_paragraphs",
default_value=False,
default_value=True,
input_type="boolean",
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",
subgroup="Amendments",
)
@ -274,7 +309,7 @@ def get_config_variables():
input_type="integer",
label="Number of (minimum) required supporters for a motion",
help_text="Choose 0 to disable the supporting system.",
weight=345,
weight=360,
group="Motions",
subgroup="Supporters",
validators=(MinValueValidator(0),),
@ -285,7 +320,7 @@ def get_config_variables():
default_value=False,
input_type="boolean",
label="Remove all supporters of a motion if a submitter edits his motion in early state",
weight=350,
weight=361,
group="Motions",
subgroup="Supporters",
)
@ -304,7 +339,7 @@ def get_config_variables():
{"value": "CAST", "display_name": "All casted ballots"},
{"value": "DISABLED", "display_name": "Disabled (no percents)"},
),
weight=355,
weight=370,
group="Motions",
subgroup="Voting and ballot papers",
)
@ -317,7 +352,7 @@ def get_config_variables():
choices=majorityMethods,
label="Required majority",
help_text="Default method to check whether a motion has reached the required majority.",
weight=357,
weight=372,
group="Motions",
subgroup="Voting and ballot papers",
)
@ -338,7 +373,7 @@ def get_config_variables():
"display_name": "Use the following custom number",
},
),
weight=360,
weight=374,
group="Motions",
subgroup="Voting and ballot papers",
)
@ -348,7 +383,7 @@ def get_config_variables():
default_value=8,
input_type="integer",
label="Custom number of ballot papers",
weight=365,
weight=376,
group="Motions",
subgroup="Voting and ballot papers",
validators=(MinValueValidator(1),),
@ -360,7 +395,7 @@ def get_config_variables():
name="motions_export_title",
default_value="Motions",
label="Title for PDF documents of motions",
weight=370,
weight=380,
group="Motions",
subgroup="PDF export",
)
@ -369,7 +404,7 @@ def get_config_variables():
name="motions_export_preamble",
default_value="",
label="Preamble text for PDF documents of motions",
weight=375,
weight=382,
group="Motions",
subgroup="PDF export",
)
@ -379,7 +414,7 @@ def get_config_variables():
default_value=False,
label="Show submitters and recommendation in table of contents",
input_type="boolean",
weight=378,
weight=384,
group="Motions",
subgroup="PDF export",
)
@ -389,7 +424,7 @@ def get_config_variables():
default_value=False,
label="Show checkbox to record decision",
input_type="boolean",
weight=379,
weight=386,
group="Motions",
subgroup="PDF export",
)

View File

@ -332,26 +332,23 @@ class Motion(RESTModelMixin, AgendaItemWithListOfSpeakersMixin, models.Model):
# Do not set an identifier.
return
# If MOTION_IDENTIFIER_WITHOUT_BLANKS is set, don't use blanks when building identifier.
without_blank = (
hasattr(settings, "MOTION_IDENTIFIER_WITHOUT_BLANKS")
and settings.MOTION_IDENTIFIER_WITHOUT_BLANKS
)
# If config 'motions_identifier_with_blank' is set, use blanks when building identifier.
with_blank = config["motions_identifier_with_blank"]
# Build prefix.
if self.is_amendment():
parent_identifier = self.parent.identifier or ""
if without_blank:
prefix = f"{parent_identifier}{config['motions_amendments_prefix']}"
if with_blank:
prefix = f"{parent_identifier} {config['motions_amendments_prefix']}"
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:
prefix = ""
else:
if without_blank:
prefix = self.category.prefix
else:
if with_blank:
prefix = f"{self.category.prefix} "
else:
prefix = self.category.prefix
self._identifier_prefix = prefix
# 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):
"""
Returns the number used in the set_identifier method with leading
zero charaters according to the settings value
MOTION_IDENTIFIER_MIN_DIGITS.
zero charaters according to the config value.
"""
result = str(number)
if (
hasattr(settings, "MOTION_IDENTIFIER_MIN_DIGITS")
and settings.MOTION_IDENTIFIER_MIN_DIGITS
):
if not isinstance(settings.MOTION_IDENTIFIER_MIN_DIGITS, int):
if config["motions_identifier_min_digits"]:
if not isinstance(config["motions_identifier_min_digits"], int):
raise ImproperlyConfigured(
"Settings value MOTION_IDENTIFIER_MIN_DIGITS must be an integer."
"Config value 'motions_identifier_min_digits' must be an integer."
)
result = (
"0" * (settings.MOTION_IDENTIFIER_MIN_DIGITS - len(str(number)))
"0" * (config["motions_identifier_min_digits"] - len(str(number)))
+ result
)
return result

View File

@ -44,7 +44,7 @@ def get_config_variables():
label="Title for access data and welcome PDF",
weight=520,
group="Participants",
subgroup="PDF",
subgroup="PDF export",
)
yield ConfigVariable(
@ -53,7 +53,7 @@ def get_config_variables():
label="Help text for access data and welcome PDF",
weight=530,
group="Participants",
subgroup="PDF",
subgroup="PDF export",
)
# TODO: Use Django's URLValidator here.
@ -64,7 +64,7 @@ def get_config_variables():
help_text="Used for QRCode in PDF of access data.",
weight=540,
group="Participants",
subgroup="PDF",
subgroup="PDF export",
)
yield ConfigVariable(
@ -74,7 +74,7 @@ def get_config_variables():
help_text="Used for WLAN QRCode in PDF of access data.",
weight=550,
group="Participants",
subgroup="PDF",
subgroup="PDF export",
)
yield ConfigVariable(
@ -84,7 +84,7 @@ def get_config_variables():
help_text="Used for WLAN QRCode in PDF of access data.",
weight=560,
group="Participants",
subgroup="PDF",
subgroup="PDF export",
)
yield ConfigVariable(
@ -101,7 +101,7 @@ def get_config_variables():
),
weight=570,
group="Participants",
subgroup="PDF",
subgroup="PDF export",
)
# Email
@ -129,7 +129,7 @@ def get_config_variables():
yield ConfigVariable(
name="users_email_subject",
default_value="Your login for {event_name}",
default_value="OpenSlides access data",
input_type="string",
label="Email subject",
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 pytest
from django.conf import settings
from django.contrib.auth import get_user_model
from django.urls import reverse
from rest_framework import status
@ -295,7 +294,7 @@ class CreateMotion(TestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
motion = Motion.objects.get()
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):
submitter_1 = get_user_model().objects.create_user(
@ -1942,24 +1941,25 @@ class NumberMotionsInCategories(TestCase):
def test_with_blanks(self):
config["motions_amendments_prefix"] = "-X"
settings.MOTION_IDENTIFIER_WITHOUT_BLANKS = True
settings.MOTION_IDENTIFIER_MIN_DIGITS = 3
config["motions_identifier_with_blank"] = False
config["motions_identifier_min_digits"] = 3
response = self.client.post(reverse("category-numbering", args=[self.A.pk]))
settings.MOTION_IDENTIFIER_WITHOUT_BLANKS = False
settings.MOTION_IDENTIFIER_MIN_DIGITS = 1
config["motions_identifier_with_blank"] = True
config["motions_identifier_min_digits"] = 1
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.M3.pk).identifier, "test_A002")
self.assertEqual(Motion.objects.get(pk=self.M2.pk).identifier, "test_C003")
self.assertEqual(Motion.objects.get(pk=self.M1.pk).identifier, "test_A 001")
self.assertEqual(Motion.objects.get(pk=self.M3.pk).identifier, "test_A 002")
self.assertEqual(Motion.objects.get(pk=self.M2.pk).identifier, "test_C 003")
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(
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(
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):

View File

@ -89,13 +89,14 @@ class ModelTest(TestCase):
parent + a suffix.
"""
config["motions_amendments_enabled"] = True
config["motions_identifier_with_blank"] = False
self.motion.identifier = "Parent identifier"
self.motion.save()
motion = Motion(parent=self.motion)
motion.set_identifier()
self.assertEqual(motion.identifier, "Parent identifier - 1")
self.assertEqual(motion.identifier, "Parent identifier-1")
def test_set_identifier_second_amendment(self):
"""
@ -110,4 +111,4 @@ class ModelTest(TestCase):
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, "")
# Customization of OpenSlides apps
MOTION_IDENTIFIER_MIN_DIGITS = 1
# Special settings only for testing
# Use a faster password hasher.

View File

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