(upload_domain, user_specs, upload_user, upload_record_id,
                                               group_memoizer=None,
                                               update_progress=None)
return ret
Creates and Updates CommCare Users
    For the associated web user username passed, for each CommCareUser
        if corresponding web user is present
            if web user has confirmed account but not a member of domain
                adds them to the domain with same role and primary location as the CommCareUser
            if already a member of domain
                update their role and primary location to be same as that of the CommCareUser
        else creates or updates user invitation
           sets Invitation with the CommCare user's role and primary location
    All changes to users only, are tracked using UserChangeLogger, as an audit trail.
Creates and Updates CommCare Users
    For the associated web user username passed, for each CommCareUser
        if corresponding web user is present
            if web user has confirmed account but not a member of domain
                adds them to the domain with same role and primary location as the CommCareUser
            if already a member of domain
                update their role and primary location to be same as that of the CommCareUser
        else creates or updates user invitation
           sets Invitation with the CommCare user's role and primary location
    All changes to users only, are tracked using UserChangeLogger, as an audit trail.
Creates and Updates CommCare Users For the associated web user username passed for each CommCareUser if corresponding web user is present if web user has confirmed account but not a member of domain adds them to the domain with same role and primary location as the CommCareUser if already a member of domain update their role and primary location to be same as that of the CommCareUser else creates or updates user invitation sets Invitation with the CommCare user s role and primary location All changes to users only are tracked using UserChangeLogger as an audit trail .
def create_or_update_commcare_users_and_groups(upload_domain, user_specs, upload_user, upload_record_id,
                                               group_memoizer=None,
                                               update_progress=None):
    """"
    Creates and Updates CommCare Users
    For the associated web user username passed, for each CommCareUser
        if corresponding web user is present
            if web user has confirmed account but not a member of domain
                adds them to the domain with same role and primary location as the CommCareUser
            if already a member of domain
                update their role and primary location to be same as that of the CommCareUser
        else creates or updates user invitation
           sets Invitation with the CommCare user's role and primary location
    All changes to users only, are tracked using UserChangeLogger, as an audit trail.
    """
    from corehq.apps.user_importer.helpers import CommCareUserImporter, WebUserImporter

    domain_info_by_domain = {}

    ret = {"errors": [], "rows": []}
    current = 0

    for row in user_specs:
        if update_progress:
            update_progress(current)
            current += 1

        username = row.get('username')
        domain = row.get('domain') or upload_domain
        username = normalize_username(str(username), domain) if username else None
        status_row = {
            'username': username,
            'row': row,
        }

        try:
            domain_info = get_domain_info(domain, upload_domain, user_specs, domain_info_by_domain,
                                        group_memoizer)

            for validator in domain_info.validators:
                validator(row)
        except UserUploadError as e:
            status_row['flag'] = str(e)
            ret['rows'].append(status_row)
            continue

        data = row.get('data', {})
        email = row.get('email')
        group_names = list(map(str, row.get('group') or []))
        language = row.get('language')
        name = row.get('name')
        password = row.get('password')
        uncategorized_data = row.get('uncategorized_data', {})
        user_id = row.get('user_id')
        location_codes = row.get('location_code', []) if 'location_code' in row else None
        location_codes = format_location_codes(location_codes)
        role = row.get('role', None)
        profile = row.get('user_profile', None)
        web_user_username = row.get('web_user')
        phone_numbers = row.get('phone-number', []) if 'phone-number' in row else None

        try:
            password = str(password) if password else None

            is_active = spec_value_to_boolean_or_none(row, 'is_active')
            is_account_confirmed = spec_value_to_boolean_or_none(row, 'is_account_confirmed')
            send_account_confirmation_email = spec_value_to_boolean_or_none(row, 'send_confirmation_email')
            remove_web_user = spec_value_to_boolean_or_none(row, 'remove_web_user')

            user = _get_or_create_commcare_user(domain, user_id, username, is_account_confirmed,
                                                web_user_username, password, upload_user)
            commcare_user_importer = CommCareUserImporter(upload_domain, domain, user, upload_user,
                                                        is_new_user=not bool(user_id),
                                                        via=USER_CHANGE_VIA_BULK_IMPORTER,
                                                        upload_record_id=upload_record_id)
            if user_id:
                if is_password(password):
                    commcare_user_importer.update_password(password)
                    # overwrite password in results so we do not save it to the db
                    status_row['row']['password'] = 'REDACTED'
                status_row['flag'] = 'updated'
            else:
                status_row['flag'] = 'created'

            if phone_numbers is not None:
                phone_numbers = clean_phone_numbers(phone_numbers)
                commcare_user_importer.update_phone_numbers(phone_numbers)

            if name:
                commcare_user_importer.update_name(name)

            commcare_user_importer.update_user_data(data, uncategorized_data, profile, domain_info)

            if language:
                commcare_user_importer.update_language(language)
            if email:
                commcare_user_importer.update_email(email)
            if is_active is not None:
                commcare_user_importer.update_status(is_active)

            # Do this here so that we validate the location code before we
            # save any other information to the user, this way either all of
            # the user's information is updated, or none of it
            # Do not update location info if the column is not included at all
            if domain_info.can_assign_locations and location_codes is not None:
                commcare_user_importer.update_locations(location_codes, domain_info)

            if role:
                role_qualified_id = domain_info.roles_by_name[role]
                commcare_user_importer.update_role(role_qualified_id)
            elif not commcare_user_importer.logger.is_new_user and 'role' in row:
                commcare_user_importer.update_role('none')

            if web_user_username:
                user.update_metadata({'login_as_user': web_user_username})

            user.save()
            log = commcare_user_importer.save_log()

            if web_user_username:
                check_can_upload_web_users(upload_user)
                web_user = CouchUser.get_by_username(web_user_username)
                if web_user:
                    web_user_importer = WebUserImporter(upload_domain, domain, web_user, upload_user,
                                                        is_new_user=False,
                                                        via=USER_CHANGE_VIA_BULK_IMPORTER,
                                                        upload_record_id=upload_record_id)
                    user_change_logger = web_user_importer.logger
                else:
                    web_user_importer = None
                    user_change_logger = None
                if remove_web_user:
                    remove_web_user_from_domain(domain, web_user, username, upload_user,
                                                user_change_logger)
                else:
                    check_user_role(username, role)
                    if not web_user and is_account_confirmed:
                        raise UserUploadError(_(
                            "You can only set 'Is Account Confirmed' to 'True' on an existing Web User. "
                            f"{web_user_username} is a new username."
                        ).format(web_user_username=web_user_username))
                    if web_user and not web_user.is_member_of(domain) and is_account_confirmed:
                        # add confirmed account to domain
                        # role_qualified_id would be be present here as confirmed in check_user_role
                        web_user_importer.add_to_domain(role_qualified_id, user.location_id)
                    elif not web_user or not web_user.is_member_of(domain):
                        create_or_update_web_user_invite(web_user_username, domain, role_qualified_id,
                                                        upload_user, user.location_id, user_change_logger,
                                                        send_email=send_account_confirmation_email)
                    elif web_user.is_member_of(domain):
                        # edit existing user in the domain
                        web_user_importer.update_role(role_qualified_id)
                        if location_codes is not None:
                            web_user_importer.update_primary_location(user.location_id)
                        web_user.save()
                if web_user_importer:
                    web_user_importer.save_log()
            if send_account_confirmation_email and not web_user_username:
                send_account_confirmation_if_necessary(user)

            if is_password(password):
                # Without this line, digest auth doesn't work.
                # With this line, digest auth works.
                # Other than that, I'm not sure what's going on
                # Passing use_primary_db=True because of https://dimagi-dev.atlassian.net/browse/ICDS-465
                user.get_django_user(use_primary_db=True).check_password(password)

            group_change_message = commcare_user_importer.update_user_groups(domain_info, group_names)

            try:
                domain_info.group_memoizer.save_updated()
            except BulkSaveError as e:
                _error_message = (
                    "Oops! We were not able to save some of your group changes. "
                    "Please make sure no one else is editing your groups "
                    "and try again."
                )
                logging.exception((
                    'BulkSaveError saving groups. '
                    'User saw error message "%s". Errors: %s'
                ) % (_error_message, e.errors))
                ret['errors'].append(_error_message)

            if log and group_change_message:
                log.change_messages.update(group_change_message)
                log.save()
            elif group_change_message:
                log = commcare_user_importer.logger.save_only_group_changes(group_change_message)

        except ValidationError as e:
            status_row['flag'] = e.message
        except (UserUploadError, CouchUser.Inconsistent) as e:
            status_row['flag'] = str(e)

        ret["rows"].append(status_row)

    return ret
def create_or_update_commcare_users_and_groups ( upload_domain , user_specs , upload_user , upload_record_id , group_memoizer = None , update_progress = None ) : from corehq . apps . user_importer . helpers import CommCareUserImporter , WebUserImporter domain_info_by_domain = { } ret = { "errors" : [ ] , "rows" : [ ] } current = 0 for row in user_specs : if update_progress : update_progress ( current ) current += 1 username = row . get ( 'username' ) domain = row . get ( 'domain' ) or upload_domain username = normalize_username ( str ( username ) , domain ) if username else None status_row = { 'username' : username , 'row' : row , } try : domain_info = get_domain_info ( domain , upload_domain , user_specs , domain_info_by_domain , group_memoizer ) for validator in domain_info . validators : validator ( row ) except UserUploadError as e : status_row [ 'flag' ] = str ( e ) ret [ 'rows' ] . append ( status_row ) continue data = row . get ( 'data' , { } ) email = row . get ( 'email' ) group_names = list ( map ( str , row . get ( 'group' ) or [ ] ) ) language = row . get ( 'language' ) name = row . get ( 'name' ) password = row . get ( 'password' ) uncategorized_data = row . get ( 'uncategorized_data' , { } ) user_id = row . get ( 'user_id' ) location_codes = row . get ( 'location_code' , [ ] ) if 'location_code' in row else None location_codes = format_location_codes ( location_codes ) role = row . get ( 'role' , None ) profile = row . get ( 'user_profile' , None ) web_user_username = row . get ( 'web_user' ) phone_numbers = row . get ( 'phone-number' , [ ] ) if 'phone-number' in row else None try : password = str ( password ) if password else None is_active = spec_value_to_boolean_or_none ( row , 'is_active' ) is_account_confirmed = spec_value_to_boolean_or_none ( row , 'is_account_confirmed' ) send_account_confirmation_email = spec_value_to_boolean_or_none ( row , 'send_confirmation_email' ) remove_web_user = spec_value_to_boolean_or_none ( row , 'remove_web_user' ) user = _get_or_create_commcare_user ( domain , user_id , username , is_account_confirmed , web_user_username , password , upload_user ) commcare_user_importer = CommCareUserImporter ( upload_domain , domain , user , upload_user , is_new_user = not bool ( user_id ) , via = USER_CHANGE_VIA_BULK_IMPORTER , upload_record_id = upload_record_id ) if user_id : if is_password ( password ) : commcare_user_importer . update_password ( password ) # overwrite password in results so we do not save it to the db status_row [ 'row' ] [ 'password' ] = 'REDACTED' status_row [ 'flag' ] = 'updated' else : status_row [ 'flag' ] = 'created' if phone_numbers is not None : phone_numbers = clean_phone_numbers ( phone_numbers ) commcare_user_importer . update_phone_numbers ( phone_numbers ) if name : commcare_user_importer . update_name ( name ) commcare_user_importer . update_user_data ( data , uncategorized_data , profile , domain_info ) if language : commcare_user_importer . update_language ( language ) if email : commcare_user_importer . update_email ( email ) if is_active is not None : commcare_user_importer . update_status ( is_active ) # Do this here so that we validate the location code before we # save any other information to the user, this way either all of # the user's information is updated, or none of it # Do not update location info if the column is not included at all if domain_info . can_assign_locations and location_codes is not None : commcare_user_importer . update_locations ( location_codes , domain_info ) if role : role_qualified_id = domain_info . roles_by_name [ role ] commcare_user_importer . update_role ( role_qualified_id ) elif not commcare_user_importer . logger . is_new_user and 'role' in row : commcare_user_importer . update_role ( 'none' ) if web_user_username : user . update_metadata ( { 'login_as_user' : web_user_username } ) user . save ( ) log = commcare_user_importer . save_log ( ) if web_user_username : check_can_upload_web_users ( upload_user ) web_user = CouchUser . get_by_username ( web_user_username ) if web_user : web_user_importer = WebUserImporter ( upload_domain , domain , web_user , upload_user , is_new_user = False , via = USER_CHANGE_VIA_BULK_IMPORTER , upload_record_id = upload_record_id ) user_change_logger = web_user_importer . logger else : web_user_importer = None user_change_logger = None if remove_web_user : remove_web_user_from_domain ( domain , web_user , username , upload_user , user_change_logger ) else : check_user_role ( username , role ) if not web_user and is_account_confirmed : raise UserUploadError ( _ ( "You can only set 'Is Account Confirmed' to 'True' on an existing Web User. " f"{web_user_username} is a new username." ) . format ( web_user_username = web_user_username ) ) if web_user and not web_user . is_member_of ( domain ) and is_account_confirmed : # add confirmed account to domain # role_qualified_id would be be present here as confirmed in check_user_role web_user_importer . add_to_domain ( role_qualified_id , user . location_id ) elif not web_user or not web_user . is_member_of ( domain ) : create_or_update_web_user_invite ( web_user_username , domain , role_qualified_id , upload_user , user . location_id , user_change_logger , send_email = send_account_confirmation_email ) elif web_user . is_member_of ( domain ) : # edit existing user in the domain web_user_importer . update_role ( role_qualified_id ) if location_codes is not None : web_user_importer . update_primary_location ( user . location_id ) web_user . save ( ) if web_user_importer : web_user_importer . save_log ( ) if send_account_confirmation_email and not web_user_username : send_account_confirmation_if_necessary ( user ) if is_password ( password ) : # Without this line, digest auth doesn't work. # With this line, digest auth works. # Other than that, I'm not sure what's going on # Passing use_primary_db=True because of https://dimagi-dev.atlassian.net/browse/ICDS-465 user . get_django_user ( use_primary_db = True ) . check_password ( password ) group_change_message = commcare_user_importer . update_user_groups ( domain_info , group_names ) try : domain_info . group_memoizer . save_updated ( ) except BulkSaveError as e : _error_message = ( "Oops! We were not able to save some of your group changes. " "Please make sure no one else is editing your groups " "and try again." ) logging . exception ( ( 'BulkSaveError saving groups. ' 'User saw error message "%s". Errors: %s' ) % ( _error_message , e . errors ) ) ret [ 'errors' ] . append ( _error_message ) if log and group_change_message : log . change_messages . update ( group_change_message ) log . save ( ) elif group_change_message : log = commcare_user_importer . logger . save_only_group_changes ( group_change_message ) except ValidationError as e : status_row [ 'flag' ] = e . message except ( UserUploadError , CouchUser . Inconsistent ) as e : status_row [ 'flag' ] = str ( e ) ret [ "rows" ] . append ( status_row ) return ret