From 478126f1e3d6e5e1e0e2ce7ea1dffdbfbab4114c Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Tue, 3 Oct 2023 23:17:09 -0500 Subject: [PATCH] Improve the `core-office anonymize` command somewhat API is not good enough for this, need to write direct SQL instead this "mostly" anonymizes `custdata` and `meminfo` but still needs to also anonymize probably `CustomerAccounts` and `Customers`, as well as `employees` and possibly others..? --- rattail_corepos/app.py | 4 +- rattail_corepos/corepos/office/commands.py | 76 ++++++++++++++++++---- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/rattail_corepos/app.py b/rattail_corepos/app.py index 5b0465e..69a2d06 100644 --- a/rattail_corepos/app.py +++ b/rattail_corepos/app.py @@ -54,8 +54,10 @@ class CoreHandler(GenericHandler): from corepos.db.office_trans import model return model - def make_session_office_op(self, **kwargs): + def make_session_office_op(self, dbkey='default', **kwargs): from corepos.db.office_op import Session + if 'bind' not in kwargs: + kwargs['bind'] = self.config.core_office_op_engines[dbkey] return Session(**kwargs) def make_session_office_trans(self, **kwargs): diff --git a/rattail_corepos/corepos/office/commands.py b/rattail_corepos/corepos/office/commands.py index 08f7b15..179baf2 100644 --- a/rattail_corepos/corepos/office/commands.py +++ b/rattail_corepos/corepos/office/commands.py @@ -25,6 +25,7 @@ CORE Office commands """ import logging +import random import sys import requests @@ -66,12 +67,21 @@ class Command(commands.Command): class Anonymize(commands.Subcommand): """ - Update customer etc. data to make it anonymous + Make anonymous (randomize) all customer names etc. """ name = 'anonymize' description = __doc__.strip() def add_parser_args(self, parser): + + parser.add_argument('--dbkey', metavar='KEY', default='default', + help="Config key for CORE POS database engine to be updated. " + "This key must be [corepos.db.office_op] section of your " + "config file. Defaults to 'default'.") + + parser.add_argument('--dry-run', action='store_true', + help="Go through the full motions and allow logging etc. to " + "occur, but rollback (abort) the transaction at the end.") parser.add_argument('--force', '-f', action='store_true', help="Do not prompt for confirmation.") @@ -90,21 +100,63 @@ class Anonymize(commands.Subcommand): "\tpip install names\n") sys.exit(2) - api = self.app.get_corepos_handler().make_webapi() - members = get_core_members(self.config, api, progress=self.progress) + try: + import us + except ImportError: + self.stderr.write("must install the `us` package first!\n\n" + "\tpip install us\n") + sys.exit(2) - def anonymize(member, i): - data = dict(member) - cardno = data.pop('cardNo') + self.anonymize_all(args) - for customer in data['customers']: - customer['firstName'] = names.get_first_name() - customer['lastName'] = names.get_last_name() + def anonymize_all(self, args): + core_handler = self.app.get_corepos_handler() + op_session = core_handler.make_session_office_op(dbkey=args.dbkey) + op_model = core_handler.get_model_office_op() - api.set_member(cardno, **data) + states = [state.abbr for state in us.states.STATES] - self.progress_loop(anonymize, members, - message="Anonymizing all member data") + members = op_session.query(op_model.MemberInfo)\ + .all() + + def anon_meminfo(member, i): + member.first_name = names.get_first_name() + member.last_name = names.get_last_name() + member.other_first_name = names.get_first_name() + member.other_last_name = names.get_last_name() + # member.city = self.random_city() + member.state = random.choice(states) + # member.zipcode = self.random_zipcode() + member.zipcode = '12345' # TODO + member.phone = self.random_phone() + member.email = self.random_email() + member.notes.clear() + + self.progress_loop(anon_meminfo, members, + message="Anonymizing meminfo") + + customers = op_session.query(op_model.CustomerClassic)\ + .all() + + def anon_custdata(customer, i): + customer.first_name = names.get_first_name() + customer.last_name = names.get_last_name() + + self.progress_loop(anon_custdata, customers, + message="Anonymizing custdata") + + self.finalize_session(op_session, dry_run=args.dry_run) + + def random_phone(self): + digits = [random.choice('0123456789') + for i in range(10)] + return self.app.normalize_phone_number(''.join(digits)) + + def random_email(self): + import names + name = names.get_full_name() + name = name.replace(' ', '_') + return f'{name}@mailinator.com' class CoreDBImportSubcommand(commands.ImportSubcommand):