def test_remove(self): flags = Flags("placeholders:bar:baz, foo:1, bar") flags.remove("foo") self.assertEqual(flags.items(), {("placeholders", "bar", "baz"), "bar"}) flags.remove("bar") self.assertEqual(flags.items(), {("placeholders", "bar", "baz")})
def edit_context(request, pk): unit = get_object_or_404(Unit, pk=pk) if not unit.is_source and not unit.translation.component.is_glossary: raise Http404("Non source unit!") do_add = "addflag" in request.POST if do_add or "removeflag" in request.POST: if not request.user.has_perm("unit.flag", unit.translation): raise PermissionDenied() flag = request.POST.get("addflag", request.POST.get("removeflag")) flags = Flags(unit.extra_flags) if do_add: flags.merge(flag) else: flags.remove(flag) new_flags = flags.format() if new_flags != unit.extra_flags: unit.extra_flags = new_flags unit.save(same_content=True, update_fields=["extra_flags"]) else: if not request.user.has_perm("source.edit", unit.translation): raise PermissionDenied() form = ContextForm(request.POST, instance=unit, user=request.user) if form.is_valid(): form.save() else: messages.error(request, _("Failed to change additional string info!")) show_form_errors(request, form) return redirect_next(request.POST.get("next"), unit.get_absolute_url())
def bulk_edit(request, project, component=None, lang=None): obj, unit_set, context = parse_url(request, project, component, lang) if not request.user.has_perm('translation.auto', obj): raise PermissionDenied() form = BulkEditForm(request.user, obj, request.POST, project=context['project']) if not form.is_valid(): messages.error(request, _('Failed to process form!')) show_form_errors(request, form) return redirect(obj) target_state = int(form.cleaned_data['state']) add_flags = Flags(form.cleaned_data['add_flags']) remove_flags = Flags(form.cleaned_data['remove_flags']) add_labels = form.cleaned_data['add_labels'] remove_labels = form.cleaned_data['remove_labels'] matching = unit_set.search(form.cleaned_data['q']) updated = 0 with transaction.atomic(): for unit in matching.select_for_update(): if not request.user.has_perm('unit.edit', unit): continue if target_state != -1 and unit.state: unit.translate( request.user, unit.target, target_state, change_action=Change.ACTION_MASS_STATE, ) updated += 1 if add_flags or remove_flags: flags = Flags(unit.source_info.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) unit.source_info.extra_flags = flags.format() unit.source_info.save(update_fields=['extra_flags']) updated += 1 if add_labels: unit.source_info.labels.add(*add_labels) updated += 1 if remove_labels: unit.source_info.labels.remove(*remove_labels) updated += 1 import_message( request, updated, _('Bulk edit completed, no strings were updated.'), ungettext( 'Bulk edit completed, %d string was updated.', 'Bulk edit completed, %d strings were updated.', updated, ), ) return redirect(obj)
def bulk_perform( user, unit_set, query, target_state, add_flags, remove_flags, add_labels, remove_labels, ): matching = unit_set.search(query) target_state = int(target_state) add_flags = Flags(add_flags) remove_flags = Flags(remove_flags) cleanups = {} preloaded_sources = False updated = 0 with transaction.atomic(): for unit in matching.select_for_update(): if not preloaded_sources: unit.translation.component.preload_sources() preloaded_sources = True if user is not None and not user.has_perm("unit.edit", unit): continue updated += 1 if (target_state != -1 and unit.state > STATE_EMPTY and unit.state < STATE_READONLY): unit.translate( user, unit.target, target_state, change_action=Change.ACTION_BULK_EDIT, propagate=False, ) if add_flags or remove_flags: flags = Flags(unit.source_info.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) unit.source_info.is_bulk_edit = True unit.source_info.extra_flags = flags.format() unit.source_info.save(update_fields=["extra_flags"]) cleanups[ unit.translation.component.pk] = unit.translation.component if add_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.add(*add_labels) cleanups[ unit.translation.component.pk] = unit.translation.component if remove_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.remove(*remove_labels) cleanups[ unit.translation.component.pk] = unit.translation.component for component in cleanups.values(): component.invalidate_stats_deep() return updated
def post_uninstall(self): try: target_translation = self.get_target_translation(self.instance.component) flags = Flags(target_translation.check_flags) flags.remove("ignore-all-checks") target_translation.check_flags = flags.format() target_translation.save(update_fields=["check_flags"]) except Translation.DoesNotExist: pass super().post_uninstall()
def bulk_perform( user, unit_set, query, target_state, add_flags, remove_flags, add_labels, remove_labels, ): matching = unit_set.search(query) components = Component.objects.filter( id__in=matching.values_list("translation__component_id", flat=True)) target_state = int(target_state) add_flags = Flags(add_flags) remove_flags = Flags(remove_flags) updated = 0 for component in components: component.preload_sources() with transaction.atomic(), component.lock(): for unit in matching.filter( translation__component=component).select_for_update(): if user is not None and not user.has_perm("unit.edit", unit): continue updated += 1 if (target_state != -1 and unit.state > STATE_EMPTY and unit.state < STATE_READONLY): unit.translate( user, unit.target, target_state, change_action=Change.ACTION_BULK_EDIT, propagate=False, ) if add_flags or remove_flags: flags = Flags(unit.source_info.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) unit.source_info.is_bulk_edit = True unit.source_info.extra_flags = flags.format() unit.source_info.save(update_fields=["extra_flags"]) if add_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.add(*add_labels) if remove_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.remove(*remove_labels) component.invalidate_stats_deep() return updated
def bulk_perform( user, unit_set, query, target_state, add_flags, remove_flags, add_labels, remove_labels, ): matching = unit_set.search(query) target_state = int(target_state) add_flags = Flags(add_flags) remove_flags = Flags(remove_flags) updated = 0 with transaction.atomic(): for unit in matching.select_for_update(): if user is not None and not user.has_perm("unit.edit", unit): continue if target_state != -1 and unit.state: unit.translate( user, unit.target, target_state, change_action=Change.ACTION_MASS_STATE, ) updated += 1 if add_flags or remove_flags: flags = Flags(unit.source_info.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) unit.source_info.extra_flags = flags.format() unit.source_info.save(update_fields=["extra_flags"]) updated += 1 if add_labels: unit.source_info.labels.add(*add_labels) updated += 1 if remove_labels: unit.source_info.labels.remove(*remove_labels) updated += 1 return updated
def flags(self): """Return flags or typecomments from units.""" flags = Flags(*self.mainunit.typecomments) flags.remove({"fuzzy"}) return flags.format()
def bulk_perform( user, unit_set, query, target_state, add_flags, remove_flags, add_labels, remove_labels, ): matching = unit_set.search(query).prefetch() components = Component.objects.filter( id__in=matching.values_list("translation__component_id", flat=True)) target_state = int(target_state) add_flags = Flags(add_flags) remove_flags = Flags(remove_flags) updated = 0 for component in components: with transaction.atomic(), component.lock(): component.preload_sources() component.commit_pending("bulk edit", user) component_units = matching.filter( translation__component=component).select_for_update() can_edit_source = user is None or user.has_perm( "source.edit", component) update_unit_ids = [] source_units = [] for unit in component_units: changed = False source_unit = unit.source_unit if (target_state != -1 and (user is None or user.has_perm("unit.edit", unit)) and target_state != unit.state and unit.state in EDITABLE_STATES): # Create change object for edit, update is done outside the looop unit.generate_change(user, user, Change.ACTION_BULK_EDIT, check_new=False) changed = True update_unit_ids.append(unit.pk) if unit.is_source: source_units.append(unit) if can_edit_source: if add_flags or remove_flags: flags = Flags(source_unit.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) new_flags = flags.format() if source_unit.extra_flags != new_flags: source_unit.is_bulk_edit = True source_unit.extra_flags = new_flags source_unit.save(update_fields=["extra_flags"]) changed = True if add_labels: source_unit.is_bulk_edit = True source_unit.labels.add(*add_labels) changed = True if remove_labels: source_unit.is_bulk_edit = True source_unit.labels.remove(*remove_labels) changed = True if changed: updated += 1 if target_state != -1: # Bulk update state Unit.objects.filter(pk__in=update_unit_ids).update( pending=True, state=target_state) # Fire source_change event in bulk for source units for unit in source_units: # The change is already done in the database, we # need it here to recalculate state of translation # units unit.is_bulk_edit = True unit.pending = True unit.state = target_state unit.source_unit_save() component.invalidate_stats_deep() return updated
def bulk_perform( user, unit_set, query, target_state, add_flags, remove_flags, add_labels, remove_labels, project, components=None, ): matching = unit_set.search(query, project=project).prefetch() if components is None: components = Component.objects.filter( id__in=matching.values_list("translation__component_id", flat=True) ) target_state = int(target_state) add_flags = Flags(add_flags) remove_flags = Flags(remove_flags) update_source = add_flags or remove_flags or add_labels or remove_labels updated = 0 for component in components: component.batch_checks = True with transaction.atomic(), component.lock(): component.commit_pending("bulk edit", user) component_units = matching.filter(translation__component=component) source_unit_ids = set() if target_state == -1: # Only fetch source unit ids here source_unit_ids = set( component_units.values_list("source_unit_id", flat=True) ) else: update_unit_ids = [] source_units = [] # Generate changes for state change for unit in component_units.select_for_update(): source_unit_ids.add(unit.source_unit_id) if ( (user is None or user.has_perm("unit.edit", unit)) and target_state != unit.state and unit.state in EDITABLE_STATES ): # Create change object for edit, update is done outside the loop unit.generate_change( user, user, Change.ACTION_BULK_EDIT, check_new=False ) updated += 1 update_unit_ids.append(unit.pk) if unit.is_source: source_units.append(unit) # Bulk update state Unit.objects.filter(pk__in=update_unit_ids).update( pending=True, state=target_state ) # Fire source_change event in bulk for source units for unit in source_units: # The change is already done in the database, we # need it here to recalculate state of translation # units unit.is_batch_update = True unit.pending = True unit.state = target_state unit.source_unit_save() if update_source and ( user is None or user.has_perm("source.edit", component) ): # Perform changes on the source units source_units = ( Unit.objects.filter(pk__in=source_unit_ids) .prefetch() .prefetch_bulk() ) if add_labels or remove_labels: source_units = source_units.prefetch_related("labels") for source_unit in source_units.select_for_update(): changed = False if add_flags or remove_flags: flags = Flags(source_unit.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) new_flags = flags.format() if source_unit.extra_flags != new_flags: source_unit.is_batch_update = True source_unit.extra_flags = new_flags source_unit.save(update_fields=["extra_flags"]) changed = True if add_labels: source_unit.is_batch_update = True source_unit.labels.add(*add_labels) changed = True if remove_labels: source_unit.is_batch_update = True source_unit.labels.remove(*remove_labels) changed = True if changed: updated += 1 component.invalidate_cache() component.update_source_checks() component.run_batched_checks() return updated
def bulk_perform( user, unit_set, query, target_state, add_flags, remove_flags, add_labels, remove_labels, ): matching = unit_set.search(query) components = Component.objects.filter( id__in=matching.values_list("translation__component_id", flat=True) ) target_state = int(target_state) add_flags = Flags(add_flags) remove_flags = Flags(remove_flags) updated = 0 for component in components: with transaction.atomic(), component.lock(): component.preload_sources() component.commit_pending("bulk edit", user) component_units = matching.filter( translation__component=component ).select_for_update() can_edit_source = user is None or user.has_perm("source.edit", component) for unit in component_units: changed = False if ( target_state != -1 and (user is None or user.has_perm("unit.edit", unit)) and target_state != unit.state and unit.state in EDITABLE_STATES ): # Create change object for edit, update is done outside the looop unit.generate_change( user, user, Change.ACTION_BULK_EDIT, check_new=False ) changed = True if can_edit_source: if add_flags or remove_flags: flags = Flags(unit.source_info.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) unit.source_info.is_bulk_edit = True unit.source_info.extra_flags = flags.format() unit.source_info.save(update_fields=["extra_flags"]) changed = True if add_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.add(*add_labels) changed = True if remove_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.remove(*remove_labels) changed = True if changed: updated += 1 if target_state != -1: component_units.filter(state__in=EDITABLE_STATES).exclude( state=target_state ).update(pending=True, state=target_state) for unit in component_units: if unit.translation.is_source: unit.is_bulk_edit = True update_source(Unit, unit) component.invalidate_stats_deep() return updated
def flags(self): flags = Flags(super().flags) flags.remove("xml-text") return flags.format()