Source code for ulaval_notify.api.session
"""This module contains the code related to the session handling.
:copyright: (c) 2018 by Antoine Gagné.
:license: MIT, see LICENSE for more details.
"""
from collections import namedtuple
from copy import copy
from threading import Lock, Timer
from requests import Request
from .constants import API_URL, BASE_URL
#: Immutable type that contains information about the session token
Token = namedtuple(
'Token', [
'client_id',
'token',
'token_type',
'expiration_date'
]
)
#: Immutable type that contains information about the current user of the API
UserDetails = namedtuple(
'UserDetails', [
'user_id',
'email',
'identification_number',
'first_name',
'last_name',
'username',
'change_number'
]
)
[docs]def refresh_periodically(interval, session_manager):
"""Refresh the session held by the session manager every given interval.
:param interval: The number of time before refreshing the session
:param session_manager: The session manager that will refresh the session
"""
session_manager.refresh()
timer = Timer(
interval,
refresh_periodically,
args=(interval, session_manager)
)
timer.start()
[docs]def create_token(token_details):
"""Create a token based on the API response.
:param token_details: The API response containing the token details
:returns: The token details
"""
return Token(
client_id=token_details['idClient'],
token=token_details['token'],
token_type=token_details['typeToken'],
expiration_date=token_details['dateExpiration']
)
[docs]def create_user_details(user_details):
"""Create a type holding the user's details based on the API response.
:param user_details: The API response containing the user's details
:returns: The user details
"""
return UserDetails(
user_id=user_details['idUtilisateurMpo'],
email=user_details['courrielPrincipal'],
identification_number=user_details['nie'],
first_name=user_details['prenom'],
last_name=user_details['nom'],
username=user_details['pseudonyme'],
change_number=user_details['numeroChangement']
)
[docs]class SessionManager:
"""The session manager handles requests to the API related to the session.
:param session: The API session
:param cookie_name: The named of the cookie to set in the session
:param cookie_content: The content of the cookie to set in the session
"""
#: The route used to refresh the session token
refresh_token_route = '{base_url}/auth/rafraichirtoken'.format(
base_url=BASE_URL
)
#: The route used to refresh the session details
refresh_session_route = '{api_url}/refreshsession'.format(
api_url=API_URL
)
def __init__(self, session, cookie_name, cookie_content):
"""Create a new session manager."""
self.__session = session
self.__lock = Lock()
self._cookie_name = cookie_name
self._update_cookies(cookie_content)
#: The details of the API session token
self.token_details = create_token(cookie_content['detailsToken'])
#: The details of the current user of the API
self.user_details = create_user_details(cookie_content['utilisateurMpo'])
def _update_cookies(self, cookie_content):
with self.__lock:
self.__session.cookies.set(
self._cookie_name,
cookie_content,
domain='monportail.ulaval.ca',
path='/public/modules/mpo-client/services/securestorage/cookie/',
secure=True
)
@property
def _session(self):
return copy(self.__session)
[docs] def send(self, request):
"""Send the given request with the current session.
:param request: The request to send to the API
:returns: The response of the API
"""
response = None
with self.__lock:
request = self._add_authentication_header(request)
response = self._session.send(
self._session.prepare_request(request)
)
return response.json() if response else response
def _add_authentication_header(self, request):
request.headers['Authorization'] = '{token_type} {token}'.format(
token_type=self.token_details.token_type,
token=self.token_details.token
)
return request
[docs] def refresh(self):
"""Refresh the session."""
self._refresh_session()
response = self._refresh_token()
self._update_cookies(response)
self.token_details = create_token(response['detailsToken'])
def _refresh_session(self):
with self.__lock:
self.__session.post(SessionManager.refresh_session_route)
def _refresh_token(self):
request = Request(
'POST',
SessionManager.refresh_token_route,
headers={
'Accept': 'application/json, text/plain, */*'
}
)
return self.send(request)