:date: 2017-10-25

===========================
Wednesday, October 25, 2017
===========================

Separate "coachings" from "clients"
===================================

While adapting the test suites after yesterday's changes for
:ticket:`2115`, I realized that it is time to split the coachings
plugin into "coachings per se" and "clients".  And :ref:`avanti` uses
only :mod:`clients <lino_xl.lib.clients>`, not :mod:`coachings
<lino_xl.lib.coachings>`.  This fixes some less visible problems,
e.g. the irritating unused menu entries for coachings in
:ref:`avanti`.

Database migration: The models :class:`ClientContact
<lino_xl.lib.clients.ClientContact>` and :class:`ClientContactType
<lino_xl.lib.clients.ClientContactType>`, and the choicelist
:class:`ClientStates <lino_xl.lib.clients.ClientStates>` were moved
from :mod:`lino_xl.lib.coachings` to :mod:`lino_xl.lib.clients`.
       
After these changes I had -as expected- some work to repair the test
suites for :ref:`welfare`.  For example at some moment there were only
23 instead of 58 clients in :mod:`lino_welfare.projects.eupen`.  This
was actually because of the *default default* value of the
:attr:`client_state` field (see :doc:`1009`).


Login via Google+
=================

I continued on :ticket:`1275`.
I reached the point where Google asks me to choose my account.

I saw this nice RuntimeError:

  You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set.
  Django can't redirect to the slash URL while maintaining POST data.
  Change your form to point to localhost:8000/complete/google-plus/ (note the trailing slash),
  or set APPEND_SLASH=False in your Django settings.
  

And later, shortly after fixing above error::
   
    AjaxExceptionResponse HTTPError: 403 Client Error: Forbidden for url: https://www.googleapis.com/plus/v1/people/me?access_token=...&alt=json

    in request POST /complete/google-plus/ (data: <QueryDict: {u'id_token': [u'...)
    TRACEBACK:
      File "/site-packages/django/core/handlers/base.py", line 185, in _get_response
        response = wrapped_callback(request, *callback_args, **callback_kwargs)
      File "/site-packages/django/views/decorators/cache.py", line 57, in _wrapped_view_func
        response = view_func(request, *args, **kwargs)
      File "/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
        return view_func(*args, **kwargs)
      File "/site-packages/social_django/utils.py", line 50, in wrapper
        return func(request, backend, *args, **kwargs)
      File "/site-packages/social_django/views.py", line 32, in complete
        redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs)
      File "/site-packages/social_core/actions.py", line 41, in do_complete
        user = backend.complete(user=user, *args, **kwargs)
      File "/site-packages/social_core/backends/base.py", line 40, in complete
        return self.auth_complete(*args, **kwargs)
      File "/site-packages/social_core/utils.py", line 252, in wrapper
        return func(*args, **kwargs)
      File "/site-packages/social_core/backends/google.py", line 144, in auth_complete
        return self.do_auth(token, response=response, *args, **kwargs)
      File "/site-packages/social_core/utils.py", line 252, in wrapper
        return func(*args, **kwargs)
      File "/site-packages/social_core/backends/oauth.py", line 403, in do_auth
        data = self.user_data(access_token, *args, **kwargs)
      File "/site-packages/social_core/backends/google.py", line 59, in user_data
        'alt': 'json'
      File "/site-packages/social_core/backends/base.py", line 233, in get_json
        return self.create_request(url, *args, **kwargs).json()
      File "/site-packages/social_core/backends/base.py", line 229, in request
        response.raise_for_status()
      File "/site-packages/requests/models.py", line 935, in raise_for_status
        raise HTTPError(http_error_msg, response=self)

    [25/Oct/2017 14:09:20] "POST /complete/google-plus/ HTTP/1.1" 400 1321


I didn't yet understand what's happening there...  In the debugger I
saw that the `X-CSRFToken
<https://docs.djangoproject.com/en/5.2/ref/csrf/>`__ was null, maybe
that's the problem?  But theoretically it is being set by the general
`beforerequest` handler defined in :xfile:`linoweb.js` ::

    Ext.Ajax.on('beforerequest', function (conn, options) {
       if (!(/^http:.*/.test(options.url) || /^https:.*/.test(options.url))) {
         if (typeof(options.headers) == "undefined") {
           options.headers = {'X-CSRFToken': Ext.util.Cookies.get('csrftoken')};
         } else {
           options.headers.extend({'X-CSRFToken': Ext.util.Cookies.get('csrftoken')});
         }                        
       }
    }, this);


To be continued...