From e992b76db06381b1c9f43bb794f4e1ca63258948 Mon Sep 17 00:00:00 2001 From: Ethan Dalool Date: Tue, 20 Dec 2016 18:31:09 -0800 Subject: [PATCH] Prevent recursive grouping of albums/tags How did I not catch this before --- constants.py | 1 + etiquette.py | 2 ++ exceptions.py | 3 +++ objects.py | 11 +++++++++-- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/constants.py b/constants.py index a70b5fc..897bdf0 100644 --- a/constants.py +++ b/constants.py @@ -98,6 +98,7 @@ ERROR_NO_SUCH_TAG = 'Doesn\'t exist' ERROR_NO_TAG_GIVEN = 'No tag name supplied' ERROR_SYNONYM_ITSELF = 'Cant apply synonym to itself' ERROR_TAG_TOO_SHORT = 'Not enough valid chars' +ERROR_RECURSIVE_GROUPING = 'Recursive grouping' WARNING_MINMAX_INVALID = 'Field "{field}": "{value}" is not a valid request. Ignored.' WARNING_MINMAX_OOO = 'Field "{field}": minimum "{min}" maximum "{max}" are out of order. Ignored.' WARNING_NO_SUCH_TAG = 'Tag "{tag}" does not exist. Ignored.' diff --git a/etiquette.py b/etiquette.py index a02739c..0383a50 100644 --- a/etiquette.py +++ b/etiquette.py @@ -685,6 +685,8 @@ def post_edit_tags(): response = {'error': constants.ERROR_SYNONYM_ITSELF, 'tagname': tag} except exceptions.NoSuchTag as e: response = {'error': constants.ERROR_NO_SUCH_TAG, 'tagname': tag} + except exceptions.RecursiveGrouping as e: + response = {'error': constants.ERROR_RECURSIVE_GROUPING, 'tagname': tag} except ValueError as e: response = {'error': e.args[0], 'tagname': tag} else: diff --git a/exceptions.py b/exceptions.py index b948b38..d109629 100644 --- a/exceptions.py +++ b/exceptions.py @@ -33,6 +33,9 @@ class UserExists(Exception): # TAG ERRORS +class RecursiveGrouping(Exception): + pass + class TagTooLong(Exception): pass diff --git a/objects.py b/objects.py index 7715281..d873416 100644 --- a/objects.py +++ b/objects.py @@ -43,15 +43,22 @@ class GroupableMixin: if not isinstance(member, type(self)): raise TypeError('Member must be of type %s' % type(self)) + # Groupables are only allowed to have 1 parent. + # Unlike photos which can exist in multiple albums. self.photodb.cur.execute('SELECT * FROM tag_group_rel WHERE memberid == ?', [member.id]) fetch = self.photodb.cur.fetchone() if fetch is not None: - if fetch[constants.SQL_TAGGROUP['parentid']] == self.id: + parent_id = fetch[constants.SQL_TAGGROUP['parentid']] + if parent_id == self.id: that_group = self else: - that_group = self.group_getter(id=fetch[constants.SQL_TAGGROUP['parentid']]) + that_group = self.group_getter(id=parent_id) raise exceptions.GroupExists('%s already in group %s' % (member.name, that_group.name)) + for parent in self.walk_parents(): + if parent.id == member.id: + raise exceptions.RecursiveGrouping('%s is an ancestor of %s' % (member.name, self.name)) + self.photodb._cached_frozen_children = None self.photodb.cur.execute('INSERT INTO tag_group_rel VALUES(?, ?)', [self.id, member.id]) if commit: