text: # -*- coding: utf-8 -*-
  '''
  Support for RallyDev
  
  .. versionadded:: 2015.8.0
  
  Requires a ``username`` and a ``password`` in ``/etc/salt/minion``:
  
  .. code-block: yaml
  
      rallydev:
        username: myuser@example.com
        password: 123pass
  '''
  
  # Import python libs
  from __future__ import absolute_import, print_function, unicode_literals
  import logging
  
  # Import salt libs
  from salt.exceptions import SaltInvocationError
  import salt.utils.http
  import salt.utils.json
  
  log = logging.getLogger(__name__)
  
  
  def __virtual__():
      '''
      Only load the module if apache is installed
      '''
      if not __opts__.get('rallydev', {}).get('username', None):
          return (False, 'The rallydev execution module failed to load: rallydev:username not defined in config.')
      if not __opts__.get('rallydev', {}).get('password', None):
          return (False, 'The rallydev execution module failed to load: rallydev:password not defined in config.')
      return True
  
  
  def _get_token():
      '''
      Get an auth token
      '''
      username = __opts__.get('rallydev', {}).get('username', None)
      password = __opts__.get('rallydev', {}).get('password', None)
      path = 'https://rally1.rallydev.com/slm/webservice/v2.0/security/authorize'
      result = salt.utils.http.query(
          path,
          decode=True,
          decode_type='json',
          text=True,
          status=True,
          username=username,
          password=password,
          cookies=True,
          persist_session=True,
          opts=__opts__,
      )
      if 'dict' not in result:
          return None
  
      return result['dict']['OperationResult']['SecurityToken']
  
  
  def _query(action=None,
             command=None,
             args=None,
             method='GET',
             header_dict=None,
             data=None):
      '''
      Make a web call to RallyDev.
      '''
      token = _get_token()
      username = __opts__.get('rallydev', {}).get('username', None)
      password = __opts__.get('rallydev', {}).get('password', None)
      path = 'https://rally1.rallydev.com/slm/webservice/v2.0/'
  
      if action:
          path += action
  
      if command:
          path += '/{0}'.format(command)
  
      log.debug('RallyDev URL: %s', path)
  
      if not isinstance(args, dict):
          args = {}
  
      args['key'] = token
  
      if header_dict is None:
          header_dict = {'Content-type': 'application/json'}
  
      if method != 'POST':
          header_dict['Accept'] = 'application/json'
  
      decode = True
      if method == 'DELETE':
          decode = False
  
      return_content = None
      result = salt.utils.http.query(
          path,
          method,
          params=args,
          data=data,
          header_dict=header_dict,
          decode=decode,
          decode_type='json',
          text=True,
          status=True,
          username=username,
          password=password,
          cookies=True,
          persist_session=True,
          opts=__opts__,
      )
      log.debug('RallyDev Response Status Code: %s', result['status'])
      if 'error' in result:
          log.error(result['error'])
          return [result['status'], result['error']]
  
      return [result['status'], result.get('dict', {})]
  
  
  def list_items(name):
      '''
      List items of a particular type
  
      CLI Examples:
  
      .. code-block:: bash
  
          salt myminion rallydev.list_<item name>s
          salt myminion rallydev.list_users
          salt myminion rallydev.list_artifacts
      '''
      status, result = _query(action=name)
      return result
  
  
  def query_item(name, query_string, order='Rank'):
      '''
      Query a type of record for one or more items. Requires a valid query string.
      See https://rally1.rallydev.com/slm/doc/webservice/introduction.jsp for
      information on query syntax.
  
      CLI Example:
  
      .. code-block:: bash
  
          salt myminion rallydev.query_<item name> <query string> [<order>]
          salt myminion rallydev.query_task '(Name contains github)'
          salt myminion rallydev.query_task '(Name contains reactor)' Rank
      '''
      status, result = _query(
          action=name,
          args={'query': query_string,
                'order': order}
      )
      return result
  
  
  def show_item(name, id_):
      '''
      Show an item
  
      CLI Example:
  
      .. code-block:: bash
  
          salt myminion rallydev.show_<item name> <item id>
      '''
      status, result = _query(action=name, command=id_)
      return result
  
  
  def update_item(name, id_, field=None, value=None, postdata=None):
      '''
      Update an item. Either a field and a value, or a chunk of POST data, may be
      used, but not both.
  
      CLI Example:
  
      .. code-block:: bash
  
          salt myminion rallydev.update_<item name> <item id> field=<field> value=<value>
          salt myminion rallydev.update_<item name> <item id> postdata=<post data>
      '''
  
      if field and value:
          if postdata:
              raise SaltInvocationError('Either a field and a value, or a chunk '
                  'of POST data, may be specified, but not both.')
          postdata = {name.title(): {field: value}}
  
      if postdata is None:
          raise SaltInvocationError('Either a field and a value, or a chunk of '
              'POST data must be specified.')
  
      status, result = _query(
          action=name,
          command=id_,
          method='POST',
          data=salt.utils.json.dumps(postdata),
      )
      return result
  
  
  def show_artifact(id_):
      '''
      Show an artifact
  
      CLI Example:
  
      .. code-block:: bash
  
          salt myminion rallydev.show_artifact <artifact id>
      '''
      return show_item('artifact', id_)
  
  
  def list_users():
      '''
      List the users
  
      CLI Example:
  
      .. code-block:: bash
  
          salt myminion rallydev.list_users
      '''
      return list_items('user')
  
  
  def show_user(id_):
      '''
      Show a user
  
      CLI Example:
  
      .. code-block:: bash
  
          salt myminion rallydev.show_user <user id>
      '''
      return show_item('user', id_)
  
  
  def update_user(id_, field, value):
      '''
      Update a user
  
      CLI Example:
  
      .. code-block:: bash
  
          salt myminion rallydev.update_user <user id> <field> <new value>
      '''
      return update_item('user', id_, field, value)
  
  
  def query_user(query_string, order='UserName'):
      '''
      Update a user
  
      CLI Example:
  
      .. code-block:: bash
  
          salt myminion rallydev.query_user '(Name contains Jo)'
      '''
      return query_item('user', query_string, order)
  