commit 9b3122390996c427dabdb73c3d292c582dea6647 Author: Cassowary Rusnov Date: Mon Nov 22 14:52:03 2021 -0800 Initial checkin diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e04319 --- /dev/null +++ b/.gitignore @@ -0,0 +1,186 @@ +# -*- mode: gitignore; -*- + +# security leaks? +.env + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# pytype +.pytype/ + +# Pyre type checker +.pyre/ + +# emacs things +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data diff --git a/README.md b/README.md new file mode 100644 index 0000000..ff74767 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Command line to dump + +FinancialType +PaymentProcessor +ContributionPage +Contact +Relationship +Group and Field tables +OptionValue and OptionGroup + +Resources urls and directories (sysetm settings) + +# Command line to load above dump diff --git a/confdump.py b/confdump.py new file mode 100644 index 0000000..b688f3c --- /dev/null +++ b/confdump.py @@ -0,0 +1,106 @@ +# CiviCRM APIv4 Configuration dumper +# Prepared for Autonomic Cooperative +# For the CAAT project + +# This tool can dump configuration to a directory, and reload configuration from a directory +# into a specified CiviCRM instance. + + +# FIXME handle username, password + +import argparse +import json +import logging +import os +import pathlib +import requests +import sys +import traceback + +from civicrmapi4.civicrmapi4 import APIv4 + +# Entities which are simply a matter of dumping and upserting without +# additional processing. +DUMP_TRIVIAL = ["FinancialType", + "PaymentProcessor", + "ContributionPage", + "Contact", + "Relationship", + "Group", + "CustomGroup", + "CustomField", + "OptionValue", + "OptionGroup"] + + +def parse_arguments() -> argparse.Namespace: + parser = argparse.ArgumentParser(prog="confdump.py", + description=("Dump configuration from a CiviCRM instance or load a previously" + "dumped configuration.")) + parser.add_argument("-v", "--verbose", help="Show debug output.", action="store_true") + parser.add_argument("baseurl", + help="The base URL for the target instance.") + subparsers = parser.add_subparsers(dest='command') + dump_sub = subparsers.add_parser('dump', help="Dump configurations.") + dump_sub.add_argument("-o", + "--output", + help="Output directory (will be created if it does not exist).", + type=pathlib.Path, + default=pathlib.Path(".")) + load_sub = subparsers.add_parser("load", help="Load configurations.") + load_sub.add_argument("-i", + "--input", + help="Input directory.", + type=pathlib.Path) + + return parser.parse_args() + + +def main() -> int: + args = parse_arguments() + + if args.verbose: + try: # for Python 3 + from http.client import HTTPConnection + except ImportError: + from httplib import HTTPConnection + HTTPConnection.debuglevel = 1 + + logging.basicConfig() # you need to initialize logging, otherwise you will not see anything from requests + logging.getLogger().setLevel(logging.DEBUG) + requests_log = logging.getLogger("urllib3") + requests_log.setLevel(logging.DEBUG) + requests_log.propagate = True + + + api = APIv4(args.baseurl) + username = os.environ.get('CIVICRM_USERNAME', None) + password = os.environ.get('CIVICRM_PASSWORD', None) + + if (username is None) or (password is None): + print("Need to specify username and password CIVICRM_USERNAME and CIVICRM_PASSWORD enivronments.") + return 1 + api.login(username, password) + if api.session is None: + print("Login failed.") + return 1 + print("log in successful") + + if args.command == "dump": + if (not args.output.exists()): + args.output.mkdir(parents=True) + if (not args.output.is_dir()): + print("Output directory exists and is not a directory") + return 1 + + for table in DUMP_TRIVIAL: + output = args.output / (table + ".json") + data = api.get(table) + if data: + print("dumping", table) + with output.open("w") as of: + of.write(json.dumps(data)) + +# main entry +if __name__ == "__main__": + sys.exit(main()) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..7507b81 --- /dev/null +++ b/tox.ini @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 120 +max-complexity = 20