""" Synchronize Kontor data between configured servers. """ import json from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser from logging import Logger from typing import Dict, List from api import ( MAPPING, EndPointNotAvailableException, Server, get_api_config, get_logger, ) parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) parser.add_argument("--verbose", "-v", action="count", default=0) parser.add_argument("--config", "-c", default="kontor-api") parser.add_argument("--dry-run", "-m", action="store_true") parser.add_argument("--to-file", "-f", action="store_true") parser.add_argument("--server", "-s") parser.add_argument("--cleanup", "-d", action="store_true") args = parser.parse_args() def create_item_id_mapping(log: Logger, data_list: List[dict]) -> Dict[str, dict]: """ create dictionary with id as key and dictionary as value. """ item_id_mapping: Dict[str, dict] = {} for data_item in data_list: log.debug(data_item) item_id_mapping[data_item["id"]] = data_item return item_id_mapping def is_different(log: Logger, first_item, second_item: dict) -> bool: """ Check dicts for differences and returns true if values are not equals, except for last_modified_date. """ check_result = False for key, value in first_item.items(): if key in second_item.keys(): if value != second_item[key]: log.info("%s: %s != %s", key, value, second_item[key]) if key == "last_modified_date": continue if not check_result: check_result = True return check_result if __name__ == "__main__": logger = get_logger(args.verbose, "kontor") logger.info("kontor.sync started") APICONFIG = get_api_config(logger, args.config) server_list: List[Server] = [] if args.server: server = APICONFIG.get_server(args.server) if server: server_list.append(server) else: server_list.extend(APICONFIG.server) export_data = {} for server in server_list: export_data[server.name] = {} for table, path in MAPPING.items(): try: data = server.request(logger, table=table) logger.info("%s: %s", table, len(data)) export_data[server.name][table] = data logger.info("%s: %s exported", table, len(data)) except EndPointNotAvailableException: logger.info("Endpoint not implemented") if args.to_file: try: json_dump = json.dumps(export_data[server.name], indent=4) file_name = f"{server.name}-data.json" with open(file_name, "w", encoding="utf-8") as dump_file: dump_file.write(json_dump) except TypeError as error: logger.info(error) for server in server_list: logger.info( "%s: %s tables exported", server.name, len(export_data[server.name]) ) if len(server_list) > 1: for table, path in MAPPING.items(): mapping = create_item_id_mapping( logger, export_data[server_list[1].name][table] ) for item in export_data[server_list[0].name][table]: logger.debug("checking %s:%s", table, item["id"]) check_item_id = item["id"] if check_item_id in mapping: check_item = mapping[check_item_id] if is_different(logger, item, check_item): logger.info( "checking values for %s != %s", item["id"], check_item["id"] ) logger.debug("diff: %s\n%s", item, check_item) if not args.dry_run: result = server_list[1].update( logger, table, check_item_id, item ) logger.info("update result: %s", result) else: logger.debug( "no changes for: %s(%s - %s)", table, item["id"], check_item["id"], ) else: logger.info( "item %s in %s missing: ", check_item_id, server_list[1].name ) if not args.dry_run: server_list[1].create(logger, table, item) logger.info("synchronization of %s finished", table) logger.info("all tables synchronized") else: logger.info("not enough server configured for sync") logger.info("kontor.sync finished")