From 92539cdf5206dcf65a1feb17b7f4dc06379067d3 Mon Sep 17 00:00:00 2001 From: Johnathan Clementi Date: Thu, 14 Nov 2024 19:28:17 -0500 Subject: [PATCH] Add mgmt command to migrate strings to non localized strings #11625 --- arches/management/commands/graph.py | 99 +++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 5 deletions(-) diff --git a/arches/management/commands/graph.py b/arches/management/commands/graph.py index f77dfe4fa33..8a57fd9523e 100644 --- a/arches/management/commands/graph.py +++ b/arches/management/commands/graph.py @@ -16,10 +16,11 @@ along with this program. If not, see . """ -from django.core.management.base import BaseCommand -from arches.app.models.graph import Graph +from django.core.management.base import BaseCommand, CommandError from django.contrib.auth.models import User -from django.db import connection, transaction +from django.db import connection, models, transaction +from arches.app.models.graph import Graph +from arches.app.models.models import Node, Widget class Command(BaseCommand): @@ -34,9 +35,14 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument( - "operation", + "-o", + "--operation", nargs="?", - choices=["publish", "create_editable_future_graphs"], + choices=[ + "publish", + "create_editable_future_graphs", + "migrate_string_nodes_to_nonlocalized", + ], help=""" Operation Type 'publish' publishes resource models indicated using the --graphs arg. @@ -53,6 +59,14 @@ def add_arguments(self, parser): default=False, help="A comma separated list of graphids to which an operation will be applied.", ) + parser.add_argument( + "-n", + "--nodes", + action="store", + dest="nodes", + default=False, + help="A comma separated list of node aliases to which an operation will be applied.", + ) parser.add_argument( "-u", "--username", @@ -94,6 +108,24 @@ def handle(self, *args, **options): if options["operation"] == "create_editable_future_graphs": self.create_editable_future_graphs() + if options["operation"] == "migrate_string_nodes_to_nonlocalized": + source_graphids = [graph.graphid for graph in self.graphs] + self.future_graphs = Graph.objects.filter( + source_identifier__in=source_graphids + ) + + if options["nodes"]: + node_aliases = [alias.strip() for alias in options["nodes"].split(",")] + self.nodes = Node.objects.filter( + graph__in=[graph.pk for graph in self.future_graphs], + alias__in=node_aliases, + datatype="string", + ).prefetch_related("cardxnodexwidget_set") + else: + raise CommandError("No node aliases provided.") + + self.migrate_string_nodes_to_nonlocalized() + def create_editable_future_graphs(self): print("\nBEGIN Create editable_future_graphs...") @@ -140,3 +172,60 @@ def publish(self, username): "update resource_instances r set graphpublicationid = publicationid from graphs g where r.graphid = g.graphid and g.graphid in %s;", (graphids,), ) + + def migrate_string_nodes_to_nonlocalized(self): + NON_LOCALIZED_STRING_WIDGET = Widget.objects.get( + name="non-localized-text-widget" + ) + + with transaction.atomic(): + for node in self.nodes: + node.datatype = "non-localized-string" + node.full_clean() + node.save() + + cross_records = node.cardxnodexwidget_set.annotate( + updated_config=models.F("config") + ) + + for cross_record in cross_records: + cross_record.config = {} + cross_record.save() + + original_default_value = cross_record.updated_config.get( + "defaultValue", None + ) + if original_default_value: + new_default_value = original_default_value["en"]["value"] + cross_record.updated_config["defaultValue"] = new_default_value + + original_widgth = cross_record.updated_config.get("width", None) + if original_widgth: + reformatted_width = original_widgth.replace("%", "") + "%" + cross_record.updated_config["width"] = reformatted_width + + cross_record.config = cross_record.updated_config + cross_record.widget = NON_LOCALIZED_STRING_WIDGET + cross_record.full_clean() + cross_record.save() + + # Refetch updated future graphs (and their updated nodes on the graph proxy model instance) + future_graphs = Graph.objects.filter( + pk__in=[future_graph.pk for future_graph in self.future_graphs] + ) + for future_graph in future_graphs: + source_graph = Graph.objects.get(pk=future_graph.source_identifier_id) + updated_source_graph = source_graph.update_from_editable_future_graph( + editable_future_graph=future_graph + ) + editable_future_graph = updated_source_graph.create_editable_future_graph() + updated_source_graph.publish( + notes="Migrated selected string nodes to non-localized string nodes" + ) + + self.stdout.write( + "The following nodes for the {0} graph have been successfully migrated to non-localized string datatype: {1}".format( + updated_source_graph.name, + ", ".join([node.alias for node in self.nodes]), + ) + )