def replace_usernames(config_file, username_replacement_csv): """ Retrieves a JWT token as the retirement service user, then calls the LMS endpoint to retrieve the list of learners awaiting retirement. Config file example: ``` client_id: xxx client_secret: xxx base_urls: lms: http://localhost:18000 ecommerce: http://localhost:18130 discovery: http://localhost:18381 credentials: http://localhost:18150 ``` Username file example: ``` current_un_1,desired_un_1 current_un_2,desired_un_2, current_un_3,desired_un_3 ``` """ if not config_file: click.echo('A config file is required.') exit(-1) if not username_replacement_csv: click.echo('A username replacement CSV file is required') exit(-1) with io.open(config_file, 'r') as config: config_yaml = yaml.safe_load(config) with io.open(username_replacement_csv, 'r') as replacement_file: csv_reader = csv.reader(replacement_file) lms_username_mappings = [{ current_username: desired_username } for (current_username, desired_username) in csv_reader] client_id = config_yaml['client_id'] client_secret = config_yaml['client_secret'] lms_base_url = config_yaml['base_urls']['lms'] ecommerce_base_url = config_yaml['base_urls']['ecommerce'] discovery_base_url = config_yaml['base_urls']['discovery'] credentials_base_url = config_yaml['base_urls']['credentials'] # Note that though partially_failed sounds better than completely_failed, # it's actually worse since the user is not consistant across DBs. # Partially failed username replacements will need to be triaged so the # user isn't in a broken state successful_replacements = [] partially_failed_replacements = [] fully_failed_replacements = [] lms_api = LmsApi(lms_base_url, lms_base_url, client_id, client_secret) ecommerce_api = EcommerceApi(lms_base_url, ecommerce_base_url, client_id, client_secret) discovery_api = DiscoveryApi(lms_base_url, discovery_base_url, client_id, client_secret) credentials_api = CredentialsApi(lms_base_url, credentials_base_url, client_id, client_secret) # Call LMS with current and desired usernames response = lms_api.replace_lms_usernames(lms_username_mappings) fully_failed_replacements += response['failed_replacements'] in_progress_replacements = response['successful_replacements'] # Step through each services endpoints with the list returned from LMS. # The LMS list has already verified usernames and made any duplicate # usernames unique (e.g. 'matt' => 'mattf56a'). We pass successful # replacements onto the next service and store all failed replacments. replacement_methods = [ ecommerce_api.replace_usernames, discovery_api.replace_usernames, credentials_api.replace_usernames, lms_api.replace_forums_usernames, ] # Iterate through the endpoints above and if the APIs return any failures # capture these in partially_failed_replacements. Only successfuly # replacements will continue to be passed to the next service. for replacement_method in replacement_methods: response = replacement_method(in_progress_replacements) partially_failed_replacements += response['failed_replacements'] in_progress_replacements = response['successful_replacements'] successful_replacements = in_progress_replacements with open('username_replacement_results.csv', 'w', newline='') as output_file: csv_writer = csv.writer(output_file) # Write header csv_writer.writerow(['Original Username', 'New Username', 'Status']) write_responses(csv_writer, successful_replacements, "SUCCESS") write_responses(csv_writer, partially_failed_replacements, "PARTIALLY FAILED") write_responses(csv_writer, fully_failed_replacements, "FAILED") if partially_failed_replacements or fully_failed_replacements: exit(-1)
def _setup_all_apis_or_exit(fail_func, fail_code, config): """ Performs setup of EdxRestClientApi instances for LMS, E-Commerce, Credentials, and Demographics, as well as fetching the learner's record from LMS and validating that it is in a state to work on. Returns the learner dict and their current stage in the retirement flow. """ try: lms_base_url = config['base_urls']['lms'] ecommerce_base_url = config['base_urls'].get('ecommerce', None) credentials_base_url = config['base_urls'].get('credentials', None) segment_base_url = config['base_urls'].get('segment', None) demographics_base_url = config['base_urls'].get('demographics', None) license_manager_base_url = config['base_urls'].get( 'license_manager', None) wordpress_base_url = config['base_urls'].get('wordpress', None) client_id = config['client_id'] client_secret = config['client_secret'] wordpress_username = config['wordpress_username'] wordpress_app_password = config['wordpress_app_password'] sailthru_key = config.get('sailthru_key', None) sailthru_secret = config.get('sailthru_secret', None) salesforce_user = config.get('salesforce_user', None) salesforce_password = config.get('salesforce_password', None) salesforce_token = config.get('salesforce_token', None) salesforce_domain = config.get('salesforce_domain', None) salesforce_assignee = config.get('salesforce_assignee', None) segment_auth_token = config.get('segment_auth_token', None) segment_workspace_slug = config.get('segment_workspace_slug', None) hubspot_api_key = config.get('hubspot_api_key', None) hubspot_aws_region = config.get('hubspot_aws_region', None) hubspot_from_address = config.get('hubspot_from_address', None) hubspot_alert_email = config.get('hubspot_alert_email', None) panel_backend_base_url = config['base_urls'].get('panel_backend', None) panel_backend_auth_token = config.get('panel_backend_auth_token', None) for state in config['retirement_pipeline']: for service, service_url in (('ECOMMERCE', ecommerce_base_url), ('CREDENTIALS', credentials_base_url), ('SEGMENT', segment_base_url), ('SAILTHRU', sailthru_key), ('HUBSPOT', hubspot_api_key), ('DEMOGRAPHICS', demographics_base_url)): if state[2] == service and service_url is None: fail_func( fail_code, 'Service URL is not configured, but required for state {}' .format(state)) config['LMS'] = LmsApi(lms_base_url, lms_base_url, client_id, client_secret) if sailthru_key: config['SAILTHRU'] = SailthruApi(sailthru_key, sailthru_secret) if salesforce_user and salesforce_password and salesforce_token: config['SALESFORCE'] = SalesforceApi(salesforce_user, salesforce_password, salesforce_token, salesforce_domain, salesforce_assignee) if hubspot_api_key: config['HUBSPOT'] = HubspotAPI(hubspot_api_key, hubspot_aws_region, hubspot_from_address, hubspot_alert_email) if ecommerce_base_url: config['ECOMMERCE'] = EcommerceApi(lms_base_url, ecommerce_base_url, client_id, client_secret) if credentials_base_url: config['CREDENTIALS'] = CredentialsApi(lms_base_url, credentials_base_url, client_id, client_secret) if demographics_base_url: config['DEMOGRAPHICS'] = DemographicsApi(lms_base_url, demographics_base_url, client_id, client_secret) if license_manager_base_url: config['LICENSE_MANAGER'] = LicenseManagerApi( lms_base_url, license_manager_base_url, client_id, client_secret, ) if segment_base_url: config['SEGMENT'] = SegmentApi(segment_base_url, segment_auth_token, segment_workspace_slug) if wordpress_base_url: config['WORDPRESS'] = WordPressAPI(wordpress_base_url, wordpress_username, wordpress_app_password) if panel_backend_base_url: config['PANEL_BACKEND'] = PanelBackendAPI( panel_backend_base_url, panel_backend_auth_token) except Exception as exc: # pylint: disable=broad-except fail_func(fail_code, 'Unexpected error occurred!', exc)
def _setup_all_apis_or_exit(fail_func, fail_code, config): """ Performs setup of EdxRestClientApi instances for LMS, E-Commerce, and Credentials, as well as fetching the learner's record from LMS and validating that it is in a state to work on. Returns the learner dict and their current stage in the retirement flow. """ try: lms_base_url = config['base_urls']['lms'] ecommerce_base_url = config['base_urls'].get('ecommerce', None) credentials_base_url = config['base_urls'].get('credentials', None) segment_base_url = config['base_urls'].get('segment', None) client_id = config['client_id'] client_secret = config['client_secret'] sailthru_key = config.get('sailthru_key', None) sailthru_secret = config.get('sailthru_secret', None) salesforce_user = config.get('salesforce_user', None) salesforce_password = config.get('salesforce_password', None) salesforce_token = config.get('salesforce_token', None) salesforce_domain = config.get('salesforce_domain', None) salesforce_assignee = config.get('salesforce_assignee', None) segment_auth_token = config.get('segment_auth_token', None) segment_workspace_slug = config.get('segment_workspace_slug', None) hubspot_api_key = config.get('hubspot_api_key', None) for state in config['retirement_pipeline']: for service, service_url in (('ECOMMERCE', ecommerce_base_url), ('CREDENTIALS', credentials_base_url), ('SEGMENT', segment_base_url), ('SAILTHRU', sailthru_key), ('HUBSPOT', hubspot_api_key)): if state[2] == service and service_url is None: fail_func( fail_code, 'Service URL is not configured, but required for state {}' .format(state)) config['LMS'] = LmsApi(lms_base_url, lms_base_url, client_id, client_secret) if sailthru_key: config['SAILTHRU'] = SailthruApi(sailthru_key, sailthru_secret) if salesforce_user and salesforce_password and salesforce_token: config['SALESFORCE'] = SalesforceApi(salesforce_user, salesforce_password, salesforce_token, salesforce_domain, salesforce_assignee) if hubspot_api_key: config['HUBSPOT'] = HubspotAPI(hubspot_api_key) if ecommerce_base_url: config['ECOMMERCE'] = EcommerceApi(lms_base_url, ecommerce_base_url, client_id, client_secret) if credentials_base_url: config['CREDENTIALS'] = CredentialsApi(lms_base_url, credentials_base_url, client_id, client_secret) if segment_base_url: config['SEGMENT'] = SegmentApi(segment_base_url, segment_auth_token, segment_workspace_slug) except Exception as exc: # pylint: disable=broad-except fail_func(fail_code, 'Unexpected error occurred!', exc)