diff --git a/re2oapi/client.py b/re2oapi/client.py index 5a5804b..9de89f9 100644 --- a/re2oapi/client.py +++ b/re2oapi/client.py @@ -57,8 +57,7 @@ class Re2oAPIClient: try: self.token = self._get_token_from_file() except exceptions.APIClientGenericError: - self.token = self._get_token_from_server() - self._save_token_to_file() + self._force_renew_token() @property def need_renew_token(self): @@ -141,6 +140,10 @@ class Re2oAPIClient: 'expiration': iso8601.parse_date(response['expiration']) } + def _force_renew_token(self): + self.token = self._get_token_from_server() + self._save_token_to_file() + def get_token(self): """Retrieves the token to use for the current connection. @@ -153,8 +156,8 @@ class Re2oAPIClient: renewed but the given credentials are not valid. """ if self.need_renew_token: - self.token = self._get_token_from_server() - self._save_token_to_file() + # Renew the token only if needed + self._force_renew_token() return self.token['token'] def _request(self, method, url, headers={}, params={}, *args, **kwargs): @@ -172,6 +175,18 @@ class Re2oAPIClient: response = getattr(requests, method)( url, headers=headers, params=params, *args, **kwargs ) + if response.status_code == requests.codes.unauthorized: + # Force re-login to the server (case of a wrong token but valid + # credentials) and then retry the request without catching errors. + self._force_renew_token() + headers.update({ + 'Authorization': 'Token {}'.format(self.get_token()) + }) + response = getattr(requests, method)( + url, headers=headers, params=params, *args, **kwargs + ) + if response.status_code == requests.codes.forbidden: + raise exceptions.PermissionDenied(method, url, self._username) response.raise_for_status() return response.json() diff --git a/re2oapi/exceptions.py b/re2oapi/exceptions.py index 4239557..54d0850 100644 --- a/re2oapi/exceptions.py +++ b/re2oapi/exceptions.py @@ -19,6 +19,9 @@ class InvalidCredentials(APIClientGenericError): template = "The credentials for {}@{} are not valid." +class PermissionDenied(APIClientGenericError): + template = "The {} request to '{}' was denied for {}." + class TokenFileNotFound(APIClientGenericError): template = "Token file at {} not found."