Compare commits

..

9 Commits

3 changed files with 36 additions and 9 deletions

View File

@ -5,9 +5,9 @@
- Install requirements `pip install -r requirements.txt` - Install requirements `pip install -r requirements.txt`
- `cp example.env .env` - `cp example.env .env`
- Edit `.env` and add creds for the production, test or development server you'll retrieve the data from. - Edit `.env` and add creds for the production, test or development server you'll retrieve the data from.
- Execute dump to retrieve base data: `env $(cat example.env) python ./confdump.py dump -o mydata INSTANCEPATH` where INSTANCEPATH is something like https://crm.dev.caat.org.uk/. - Execute dump to retrieve base data: `env $(cat .env) python ./confdump.py dump -o mydata INSTANCEPATH` where INSTANCEPATH is something like https://crm.dev.caat.org.uk/.
- **IMPORTANT!!** - If you sourced the data from live, you must delete the `.env` file or delete the creds from inside it. If you leave them in it will negate the whole purpose of having this conf dump utility, which is to provide a way of creating a local site without any sensitive data. - **IMPORTANT!!** - If you sourced the data from live, you must delete the `.env` file or delete the creds from inside it. If you leave them in it will negate the whole purpose of having this conf dump utility, which is to provide a way of creating a local site without any sensitive data.
- If your civicrm is in a docker container, load data into running local instance with: `confdump.py mysql -i mydata/ -p 63306` - If your civicrm is in a docker container, load data into running local instance with: `python confdump.py mysql -i mydata/ -p 63306`
- Otherwise use `confdump.py mysql -i mydata/ --host=<host> --db=<db> --user=<user> --password=<password>` - Otherwise use `confdump.py mysql -i mydata/ --host=<host> --db=<db> --user=<user> --password=<password>`
- Clear the cache in CiviCRM: - Clear the cache in CiviCRM:
* DOCKER: `make shell`, and then inside the shell `cd /app; ./vendor/bin/drush cc all` * DOCKER: `make shell`, and then inside the shell `cd /app; ./vendor/bin/drush cc all`

View File

@ -23,6 +23,7 @@ import MySQLdb as mysql
from collections import defaultdict from collections import defaultdict
from typing import Any, Dict, List from typing import Any, Dict, List
import civicrmapi4
from civicrmapi4.civicrmapi4 import APIv4 from civicrmapi4.civicrmapi4 import APIv4
import phpserialize import phpserialize
@ -39,7 +40,9 @@ DUMP_TRIVIAL = ["FinancialType",
"CustomGroup", "CustomGroup",
"OptionGroup", "OptionGroup",
"OptionValue", "OptionValue",
"Domain"] "Domain",
"SavedSearch",
"Tag"]
# "ContributionPage", needs payment processors & payment_processor column formatted correctly. # "ContributionPage", needs payment processors & payment_processor column formatted correctly.
@ -64,7 +67,14 @@ LOAD_TRIVIAL = ["FinancialType",
"OptionGroup", "OptionGroup",
"OptionValue", "OptionValue",
"Domain", "Domain",
"Contact"] "Contact",
"SavedSearch",
"Tag"]
WEIRD_LIST = [
("civicrm_contact", "contact_sub_type"),
("civicrm_custom_group", "extends_entity_column_value")
]
# This is a payment processor we can assign contribution pages to in order for them to work. # This is a payment processor we can assign contribution pages to in order for them to work.
# FIXME this seems to produce a non-working setup. # FIXME this seems to produce a non-working setup.
@ -109,8 +119,13 @@ def object_to_table(instr: str) -> str:
def array_to_weird_array(val: List) -> str: def array_to_weird_array(val: List) -> str:
if (val is None):
return "NULL"
return '"\x01' + ('\x01'.join([str(x) for x in val])) + '\x01"' return '"\x01' + ('\x01'.join([str(x) for x in val])) + '\x01"'
def value_to_php_serialized(val: Any) -> str:
return "'{}'".format(mysql.escape_string(phpserialize.dumps(val).decode()).decode())
def python_value_to_sql(val: Any) -> str: def python_value_to_sql(val: Any) -> str:
""" """
@ -127,7 +142,7 @@ def python_value_to_sql(val: Any) -> str:
# weird list serialization # weird list serialization
return "'" + ','.join([str(x) for x in val]) + "'" return "'" + ','.join([str(x) for x in val]) + "'"
if (type(val) == dict): if (type(val) == dict):
return "'{}'".format(mysql.escape_string(phpserialize.dumps(val).decode()).decode()) return value_to_php_serialized(val)
return "'{}'".format(mysql.escape_string(val).decode()) return "'{}'".format(mysql.escape_string(val).decode())
@ -139,8 +154,10 @@ def dict_to_insert(table: str, objdict: Dict) -> str:
values = list() values = list()
for col in columns: for col in columns:
# any weird array we have to process here if there are others # any weird array we have to process here if there are others
if table == "civicrm_contact" and col == "contact_sub_type": if (table, col) in WEIRD_LIST:
values.append(array_to_weird_array(objdict[col])) values.append(array_to_weird_array(objdict[col]))
elif table == "civicrm_saved_search" and col == "form_values":
values.append(value_to_php_serialized(objdict[col]))
else: else:
values.append(python_value_to_sql(objdict[col])) values.append(python_value_to_sql(objdict[col]))
return "REPLACE INTO {} ({}) VALUES ({});".format(table, ",".join(columns), ",".join(values)) return "REPLACE INTO {} ({}) VALUES ({});".format(table, ",".join(columns), ",".join(values))
@ -206,6 +223,16 @@ def parse_arguments() -> argparse.Namespace:
return parser.parse_args() return parser.parse_args()
def wrap_api_get(api, obj, args=None):
if args is None:
args = []
try:
return api.get(obj, args)
except civicrmapi4.civicrmapi4.CallFailed:
logging.error("Could not fetch {}".format(obj))
return []
def main() -> int: def main() -> int:
args = parse_arguments() args = parse_arguments()
@ -245,14 +272,14 @@ def main() -> int:
for table in DUMP_TRIVIAL: for table in DUMP_TRIVIAL:
output = args.output / (table + ".json") output = args.output / (table + ".json")
data = api.get(table) data = wrap_api_get(api, table)
if data: if data:
print("dumping", table) print("dumping", table)
with output.open("w") as of: with output.open("w") as of:
of.write(json.dumps(data)) of.write(json.dumps(data))
# dump org contacts # dump org contacts
output = args.output / ("Contact.json") output = args.output / ("Contact.json")
data = api.get("Contact", where=[["contact_sub_type", "CONTAINS", "Political_Party"]]) data = wrap_api_get(api, "Contact", where=[["contact_sub_type", "CONTAINS", "Political_Party"]])
if data: if data:
print("dumping parties") print("dumping parties")
with output.open("w") as of: with output.open("w") as of:

View File

@ -1,3 +1,3 @@
-e git+https://git.autonomic.zone/cas/civicrmapi4#egg=civicrmapi4 -e git+https://git.autonomic.zone/autonomic-cooperative/civicrmapi4#egg=civicrmapi4
phpserialize phpserialize
mysqlclient~=1.4.6 mysqlclient~=1.4.6