From a82aec0c33999544fa49893d55acd0bca336d2ed Mon Sep 17 00:00:00 2001 From: Elio Schmutz Date: Fri, 20 Dec 2024 16:18:46 +0100 Subject: [PATCH] Add bundle-mapper for afso_gdgs migration --- .../sg_map_afso_gdgs_migration_bundle.py | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 opengever/maintenance/scripts/customer_specific/sg_map_afso_gdgs_migration_bundle.py diff --git a/opengever/maintenance/scripts/customer_specific/sg_map_afso_gdgs_migration_bundle.py b/opengever/maintenance/scripts/customer_specific/sg_map_afso_gdgs_migration_bundle.py new file mode 100644 index 0000000..7041c34 --- /dev/null +++ b/opengever/maintenance/scripts/customer_specific/sg_map_afso_gdgs_migration_bundle.py @@ -0,0 +1,130 @@ +""" +This is a copy of sg_map_areg_bdgs_migration_bundle.py with issue-specific +adjustments. + +This script is solely intended for transforming the bundle exported as part of +TI-1703 (transforms the bundle in-place). + +It deletes all exported repository folders from the bundle, because +in this specific case every single source repository folder is mapped to +an (existing) target repository folder - therefore no complicated logic is +needed to determine which repository folders to keep. + +Dossiers are mapped to their target position according to the Excel sheet +from https://4teamwork.atlassian.net/browse/TI-1703 +""" + +from collections import OrderedDict +from opengever.maintenance.debughelpers import setup_app +from opengever.maintenance.debughelpers import setup_plone +from operator import itemgetter +from os.path import join as pjoin +import argparse +import codecs +import json +import os +import sys +import transaction + + +# TBD +MAPPING = { + # ((1, 1), ): ((9, 0, 0), ), # Example + # ((1, 0), ): ((1, 10, 0), (1, )), # Example +} + + +class BundleMapper(object): + + def __init__(self, portal, options): + self.portal = portal + self.options = options + self.bundle_dir = self.options.bundle_path + self.unmapped_dossiers = [] + + def run(self): + self.map_dossiers() + self.remove_repofolders() + + def order_dict(self, data): + ordered = OrderedDict() + ordered['guid'] = data.pop('guid') + + parent_guid = data.pop('parent_guid', None) + permissions = data.pop('_permissions', None) + + if parent_guid: + ordered['parent_guid'] = parent_guid + + ordered.update(OrderedDict(sorted(data.items()))) + + if permissions: + ordered['_permissions'] = permissions + + return ordered + + def map_dossiers(self): + dossiers_json_path = pjoin(self.bundle_dir, 'dossiers.json') + with open(dossiers_json_path) as json_file: + dossier_items = json.load(json_file) + + dossier_items = map(self.order_dict, dossier_items) + dossier_items.sort(key=itemgetter('guid')) + + for dossier in dossier_items: + parent_reference = dossier.get('parent_reference') + if not parent_reference: + continue + parent_reference = map(tuple, parent_reference) + parent_reference = tuple(parent_reference) + + new_reference = MAPPING.get(parent_reference) + if new_reference: + print('Mapped %r to %r for %s' % ( + parent_reference, new_reference, dossier['guid'])) + dossier['parent_reference'] = new_reference + else: + self.unmapped_dossiers.append(dossier) + + if self.unmapped_dossiers: + print("Unmapped parent references:") + print("Parent reference, GUID, Reference Nr.") + for dossier in self.unmapped_dossiers: + print(', '.join([ + json.dumps(dossier.get('parent_reference')), + dossier.get('guid'), + dossier.get('former_reference_number')])) + raise Exception("There are unmapped dossiers.") + + self.dump_to_jsonfile(dossier_items, dossiers_json_path) + + def remove_repofolders(self): + os.remove(pjoin(self.bundle_dir, 'repofolders.json')) + os.remove(pjoin(self.bundle_dir, 'reporoots.json')) + + def dump_to_jsonfile(self, data, json_path): + with open(json_path, 'wb') as jsonfile: + json.dump( + data, + codecs.getwriter('utf-8')(jsonfile), + ensure_ascii=False, + indent=4, + separators=(',', ': ') + ) + + +if __name__ == '__main__': + app = setup_app() + + parser = argparse.ArgumentParser() + parser.add_argument('-s', dest='site_root', default=None, + help='Absolute path to the Plone site') + parser.add_argument('bundle_path', help='Path to bundle') + + options = parser.parse_args(sys.argv[3:]) + + transaction.doom() + plone = setup_plone(app, options) + + generator = BundleMapper(plone, options) + generator.run()