===============================================
How to give user ability to change the password
===============================================

First we create a "Change password" item. While creating it we set
the "Virtual table" and "Visible" attributes to false in the
:doc:`Item Editor Dialog </admin/items/item_editor_dialog>`.
And we add to it two fields: "Old password", "New password" 

We'll use this item for displaying "Change password" dialog.

To open this dialog we add a "Change password" menu item with id "pass" in the 
index.html:

.. code-block:: html

  <div class="container">        
      <div id="taskmenu" class="navbar">        
          <div class="navbar-inner">
              <ul id="menu" class="nav">
              </ul>
              <ul id="menu-right" class="nav pull-right">
                  <li id="pass"><a href="#">Change password</a></li>
              </ul>
          </div>
      </div>            
  </div>

and in the task client module 
:doc:`on_page_loaded </refs/client/task/on_page_loaded>`
event handler add the following code:

.. code-block:: js

  if (task.change_password.can_view()) {
      $("#menu-right #pass a").click(function(e) {
          e.preventDefault();
          task.change_password.open({open_empty: true});
          task.change_password.append_record();
      });
  }
  else {
      $("#menu-right #pass a").hide();
  }
  
It will check if the user has the right to view item and then opens an empty dataset
and creates an edit form, otherwise it hides this menu item.

In the "Change password" client module we add the following code:

.. code-block:: js

  function on_edit_form_created(item) {
      item.edit_form.find("#ok-btn")
          .off('click.task')
          .on('click', function() { 
              change_password(item); 
          });
      item.edit_form.find("#cancel-btn")
          .off('click.task')
          .on('click', function() { 
              item.close_edit_form(); 
          });
  }
  
  function change_password(item) {
      item.post();
      item.server('change_password', [item.old_password.value, item.new_password.value], function(res) {
          if (res) {
              item.warning('Password has been changed. <br> The application will be reloaded.', 
                function() {
                    task.logout();
                    location.reload(); 
                });
          }
          else {
              item.alert_error("Can't change the password.");    
              item.edit();
          }
      });
  }
  
  function on_field_changed(field, lookup_item) {
      var item = field.owner;
      if (field.field_name === 'old_password') {
          item.server('check_old_password', [field.value], function(error) {
              if (error) {
                  item.alert_error(error);    
              }
          });
      }
  }
  
  function on_edit_form_close_query(item) {
      return true;
  }
  
In it we reassign **OK** and **Cancel** button click events. By default they
are defined in the task client module to save record changes to the database
and cancel editing. In the ``on_edit_form_close_query`` even handler we return 
true so the ``on_edit_form_close_query`` declared in the task client module,
that shows "Yes No Cancel" disalog won't be executed.

The ``on_field_changed`` event handler will check if old password is correct.
It and the ``change_password`` function send requests to the server to execute
functions defined in the item server module:

.. code-block:: py

  def change_password(item, old_password, new_password):
      user_id = item.session['user_info']['user_id']
      users = item.task.users.copy(handlers=False)
      users.set_where(id=user_id)
      users.open()
      same_password = item.task.check_password_hash(users.password_hash.value, old_password)
      if users.rec_count== 1 and same_password:
          users.edit()
          users.password_hash.value = item.task.generate_password_hash(new_password)
          users.post()
          users.apply()
          return True
      else:
          return False
  
  def check_old_password(item, old_password):
      user_id = item.session['user_info']['user_id']
      users = item.task.users.copy(handlers=False)
      users.set_where(id=user_id)
      users.open()
      same_password = item.task.check_password_hash(users.password_hash.value, old_password)
      if users.rec_count == 1 and same_password:
          return 
      else:
          return 'Invalid password'            

They use session to get id of the current user.

After changing the password the client reloads.
  