in src/olympia/blocklist/forms.py [0:0]
def clean_changed_version_ids(self):
data = self.cleaned_data.get('changed_version_ids', [])
errors = []
# First, check we're not creating empty blocks
# we're checking new blocks for add/change; and all blocks for other actions
for block in (bl for bl in self.blocks if not bl.id or not self.is_add_change):
version_ids = [v.id for v in block.addon_versions]
changed_ids = (v_id for v_id in data if v_id in version_ids)
blocked_ids = (v.id for v in block.addon_versions if v.is_blocked)
# for add/change we raise if there are no changed ids for this addon
# for other actions, only if there is also at least one existing blocked
# version
if (self.is_add_change or any(blocked_ids)) and not any(changed_ids):
errors.append(ValidationError(f'{block.guid} has no changed versions'))
# Second, check for duplicate version strings in reused guids.
error_string = (
'{}:{} exists more than once. All {} versions must be selected together.'
)
for block in self.blocks:
version_strs = defaultdict(set) # collect version strings together
for version in block.addon_versions:
if version.id in self.changed_version_ids_choices:
version_strs[version.version].add(version.id)
for version_str, ids in version_strs.items():
# i.e. dupe version string & some ids, but not all, are being changed.
if len(ids) > 1 and not ids.isdisjoint(data) and not ids.issubset(data):
errors.append(
ValidationError(
error_string.format(block.guid, version_str, version_str)
)
)
if errors:
raise ValidationError(errors)
return data