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)
Exemple #2
0
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)
Exemple #3
0
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)