From fdd62cb342b9d41c36c69fa51b0549f714e9cdae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Norman=20J=C3=A4ckel?= Date: Mon, 25 Jan 2016 22:10:00 +0100 Subject: [PATCH] Fixed agenda numbering. Fixed #1892. --- openslides/agenda/models.py | 44 +++++++++++++++++++---- tests/integration/agenda/test_viewsets.py | 15 ++++++++ 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/openslides/agenda/models.py b/openslides/agenda/models.py index 4bfc2983c..02cc156b9 100644 --- a/openslides/agenda/models.py +++ b/openslides/agenda/models.py @@ -21,13 +21,10 @@ class ItemManager(models.Manager): Customized model manager with special methods for agenda tree and numbering. """ - def get_only_agenda_items(self, queryset=None): + def get_only_agenda_items(self): """ Generator, which yields only agenda items. Skips hidden items. """ - if queryset is None: - queryset = self.all() - # Do not execute item.is_hidden() because this would create a lot of db queries root_items, item_children = self.get_root_and_children(only_agenda_items=True) @@ -38,6 +35,29 @@ class ItemManager(models.Manager): for item in items: yield item yield from yield_items(item_children[item.pk]) + + yield from yield_items(root_items) + + def get_only_hidden_items(self): + """ + Generator, which yields only hidden items, that means only items + which type is HIDDEN_ITEM or which are children of hidden items. + """ + # Do not execute item.is_hidden() because this would create a lot of db queries + root_items, item_children = self.get_root_and_children(only_agenda_items=False) + + def yield_items(items, parent_is_hidden=False): + """ + Generator that yields a list of items and their children. + """ + for item in items: + if parent_is_hidden or item.type == item.HIDDEN_ITEM: + item_is_hidden = True + yield item + else: + item_is_hidden = False + yield from yield_items(item_children[item.pk], parent_is_hidden=item_is_hidden) + yield from yield_items(root_items) def get_root_and_children(self, only_agenda_items=False): @@ -45,7 +65,8 @@ class ItemManager(models.Manager): Returns a list with all root items and a dictonary where the key is an item pk and the value is a list with all children of the item. - If only_agenda_items is True, the tree hides HIDDEN_ITEM. + If only_agenda_items is True, the tree hides items with type + HIDDEN_ITEM and all of their children. """ queryset = self.order_by('weight') item_children = defaultdict(list) @@ -57,7 +78,6 @@ class ItemManager(models.Manager): item_children[item.parent_id].append(item) else: root_items.append(item) - return root_items, item_children def get_tree(self, only_agenda_items=False, include_content=False): @@ -66,7 +86,8 @@ class ItemManager(models.Manager): and children, where id is the id of one agenda item and children is a generator that yields dictonaries like the one discribed. - If only_agenda_items is True, the tree hides HIDDEN_ITEM. + If only_agenda_items is True, the tree hides items with type + HIDDEN_ITEM and all of their children. If include_content is True, the yielded dictonaries have no key 'id' but a key 'item' with the entire object. @@ -133,22 +154,31 @@ class ItemManager(models.Manager): """ def walk_tree(tree, number=None): for index, tree_element in enumerate(tree): + # Calculate number of visable agenda items. if numeral_system == 'roman' and number is None: item_number = to_roman(index + 1) else: item_number = str(index + 1) if number is not None: item_number = '.'.join((number, item_number)) + # Add prefix. if config['agenda_number_prefix']: item_number_tmp = "%s %s" % (config['agenda_number_prefix'], item_number) else: item_number_tmp = item_number + # Save the new value and go down the tree. tree_element['item'].item_number = item_number_tmp tree_element['item'].save() walk_tree(tree_element['children'], item_number) + # Start numbering visable agenda items. walk_tree(self.get_tree(only_agenda_items=True, include_content=True)) + # Reset number of hidden items. + for item in self.get_only_hidden_items(): + item.item_number = '' + item.save() + class Item(RESTModelMixin, models.Model): """ diff --git a/tests/integration/agenda/test_viewsets.py b/tests/integration/agenda/test_viewsets.py index 4a7a0ff0b..05a87ee0a 100644 --- a/tests/integration/agenda/test_viewsets.py +++ b/tests/integration/agenda/test_viewsets.py @@ -288,3 +288,18 @@ class Numbering(TestCase): self.assertEqual(Item.objects.get(pk=self.item_2.pk).item_number, '') self.assertEqual(Item.objects.get(pk=self.item_2_1.pk).item_number, '') self.assertEqual(Item.objects.get(pk=self.item_3.pk).item_number, '2') + + def test_reset_numbering_with_hidden_item(self): + self.item_2.item_number = 'test_number_Cieghae6ied5ool4hiem' + self.item_2.type = Item.HIDDEN_ITEM + self.item_2.save() + self.item_2_1.item_number = 'test_number_roQueTohg7fe1Is7aemu' + self.item_2_1.save() + + response = self.client.post(reverse('item-numbering')) + + self.assertEqual(response.status_code, 200) + self.assertEqual(Item.objects.get(pk=self.item_1.pk).item_number, '1') + self.assertEqual(Item.objects.get(pk=self.item_2.pk).item_number, '') + self.assertEqual(Item.objects.get(pk=self.item_2_1.pk).item_number, '') + self.assertEqual(Item.objects.get(pk=self.item_3.pk).item_number, '2')