Ensure that a user is present.

    name
        Name of the user.

    password
        Password of the user.

    email
        Optional - Email of the user.

    is_admin
        Optional - Set user as admin user. Default: False

    fullname
        Optional - Full name of the user.

    theme
        Optional - Selected theme of the user.

    default_organization
        Optional - Set user's default organization

    organizations
        Optional - List of viewer member organizations or pairs of organization and role that the user belongs to.

    profile
        Configuration profile used to connect to the Grafana instance.
        Default is 'grafana'.


    Here is an example for using default_organization and organizations
    parameters. The user will be added as a viewer to ReadonlyOrg, as an editor
    to TestOrg and as an admin to AdminOrg. When she logs on, TestOrg will be
    the default. The state will fail if any organisation is unknown or invalid
    roles are defined.

    .. code-block:: yaml

        add_grafana_test_user:
          grafana4_user.present:
            - name: test
            - password: 1234567890
            - fullname: 'Test User'
            - default_organization: TestOrg
            - organizations:
              - ReadonlyOrg
              - TestOrg: Editor
              - Staging: Admin

def present(name,
            password,
            email=None,
            is_admin=False,
            fullname=None,
            theme=None,
            default_organization=None,
            organizations=None,
            profile='grafana'):
    '''
    Ensure that a user is present.

    name
        Name of the user.

    password
        Password of the user.

    email
        Optional - Email of the user.

    is_admin
        Optional - Set user as admin user. Default: False

    fullname
        Optional - Full name of the user.

    theme
        Optional - Selected theme of the user.

    default_organization
        Optional - Set user's default organization

    organizations
        Optional - List of viewer member organizations or pairs of organization and role that the user belongs to.

    profile
        Configuration profile used to connect to the Grafana instance.
        Default is 'grafana'.


    Here is an example for using default_organization and organizations
    parameters. The user will be added as a viewer to ReadonlyOrg, as an editor
    to TestOrg and as an admin to AdminOrg. When she logs on, TestOrg will be
    the default. The state will fail if any organisation is unknown or invalid
    roles are defined.

    .. code-block:: yaml

        add_grafana_test_user:
          grafana4_user.present:
            - name: test
            - password: 1234567890
            - fullname: 'Test User'
            - default_organization: TestOrg
            - organizations:
              - ReadonlyOrg
              - TestOrg: Editor
              - Staging: Admin
    '''
    if isinstance(profile, string_types):
        profile = __salt__['config.option'](profile)

    ret = {'name': name, 'result': None, 'comment': None, 'changes': {}}
    user = __salt__['grafana4.get_user'](name, profile)
    create = not user

    if create:
        if __opts__['test']:
            ret['comment'] = 'User {0} will be created'.format(name)
            return ret
        __salt__['grafana4.create_user'](
            login=name,
            password=password,
            email=email,
            name=fullname,
            profile=profile)
        user = __salt__['grafana4.get_user'](name, profile)
        ret['changes']['new'] = user

    user_data = __salt__['grafana4.get_user_data'](user['id'], profile=profile)

    if default_organization:
        try:
            org_id = __salt__['grafana4.get_org'](default_organization, profile)['id']
        except HTTPError as e:
            ret['comment'] = 'Error while looking up user {}\'s default grafana org {}: {}'.format(
                    name, default_organization, e)
            ret['result'] = False
            return ret
    new_data = _get_json_data(login=name, email=email, name=fullname, theme=theme,
                            orgId=org_id if default_organization else None,
                            defaults=user_data)
    old_data = _get_json_data(login=None, email=None, name=None, theme=None,
                            orgId=None,
                            defaults=user_data)
    if organizations:
        ret = _update_user_organizations(name, user['id'], organizations, ret, profile)
        if 'result' in ret and ret['result'] is False:
            return ret

    if new_data != old_data:
        if __opts__['test']:
            ret['comment'] = 'User {0} will be updated'.format(name)
            dictupdate.update(ret['changes'], deep_diff(old_data, new_data))
            return ret
        __salt__['grafana4.update_user'](user['id'], profile=profile, orgid=org_id, **new_data)
        dictupdate.update(
            ret['changes'], deep_diff(
                user_data, __salt__['grafana4.get_user_data'](user['id'])))

    if user['isAdmin'] != is_admin:
        if __opts__['test']:
            ret['comment'] = 'User {0} isAdmin status will be updated'.format(
                    name)
            return ret
        __salt__['grafana4.update_user_permissions'](
            user['id'], isGrafanaAdmin=is_admin, profile=profile)
        dictupdate.update(ret['changes'], deep_diff(
            user, __salt__['grafana4.get_user'](name, profile)))

    ret['result'] = True
    if create:
        ret['changes'] = ret['changes']['new']
        ret['comment'] = 'New user {0} added'.format(name)
    else:
        if ret['changes']:
            ret['comment'] = 'User {0} updated'.format(name)
        else:
            ret['changes'] = {}
            ret['comment'] = 'User {0} already up-to-date'.format(name)

    return ret