views: refactor http error handling

Throw ServerError in get(), post(), delete() server methods
in case of connection error or status code with an error.
Log the cause of the error to show it in the web.

Add a function wrapper into every endpoint to handle the
error redirection needed for the ServerError exception.
The wrapper is defined by adding @handle_server_errors('XXX')
on top of the function declaration, where XXX is the name
of the function (endpoint) to be invoked by the redirection.
This change removes the need of specific checks after every
request and cleanups the endpoint code.

Fix the endpoint of the main views to work with an unavailable
ogserver.
master
Alejandro Sirgo Rica 2024-12-17 13:55:36 +01:00
parent fd8da5de26
commit 05cba727e0
2 changed files with 257 additions and 705 deletions

View File

@ -6,10 +6,22 @@
# (at your option) any later version.
from ogcp import app
from flask import session, flash
from flask_babel import _
import requests
import json
class ServerError(Exception):
pass
def flash_once(message, category='message'):
if '_flashes' not in session:
session['_flashes'] = []
if (category, message) not in session['_flashes']:
flash(message, category)
class OGServer:
def __init__(self, name, ip, port, api_token):
self.name = name
@ -22,32 +34,57 @@ class OGServer:
self.URL = f'http://{self.ip}:{self.port}'
self.HEADERS = {'Authorization' : self.api_token}
def get(self, path, payload=None):
def _log_http_status_code(self, res):
if res.status_code == 400:
err_msg = _('Invalid payload')
elif res.status_code == 404:
err_msg = _('Object not found')
elif res.status_code == 405:
err_msg = _('Method not allowed')
elif res.status_code == 409:
err_msg = _('Object already exists')
elif res.status_code == 423:
err_msg = _('Object in use')
elif res.status_code == 501:
err_msg = _('Cannot connect to database')
elif res.status_code == 507:
err_msg = _('Disk full')
else:
err_msg = _(f'Received status code {res.status_code}')
flash_once(err_msg, category='error')
def _request(self, method, path, payload, expected_status):
try:
r = requests.get(f'{self.URL}{path}',
headers=self.HEADERS,
json=payload)
res = requests.request(
method,
f'{self.URL}{path}',
headers=self.HEADERS,
json=payload,
)
if res.status_code not in expected_status:
self._log_http_status_code(res)
raise ServerError
return res
except requests.exceptions.ConnectionError:
return None
return r
flash_once(_('Cannot connect to ogserver'), category='error')
except requests.exceptions.Timeout:
flash_once(_('Request to ogserver timed out'), category='error')
except requests.exceptions.TooManyRedirects:
flash_once(_('Too many redirects occurred while contacting ogserver'), category='error')
except requests.exceptions.RequestException as e:
flash_once(_('An error occurred while contacting ogserver: %(error)s', error=str(e)), category='error')
raise ServerError
def get(self, path, payload=None):
return self._request('GET', path, payload, expected_status={200})
def post(self, path, payload):
try:
r = requests.post(f'{self.URL}{path}',
headers=self.HEADERS,
json=payload)
except requests.exceptions.ConnectionError:
return None
return r
return self._request('POST', path, payload, expected_status={200, 202})
def delete(self, path, payload):
try:
r = requests.delete(f'{self.URL}{path}',
headers=self.HEADERS,
json=payload)
except requests.exceptions.ConnectionError:
return None
return r
return self._request('DELETE', path, payload, expected_status={200})
@property
def id(self):

File diff suppressed because it is too large Load Diff