Add: http custom error pages, more checks js possible error, check if file delete from storage by cli

This commit is contained in:
Stepan Zhukovsky 2023-09-14 21:36:41 +09:00
parent 431541b3cb
commit b2bea677ef
12 changed files with 129 additions and 20 deletions

View File

@ -83,29 +83,35 @@ class ArchiveViewSet(viewsets.ModelViewSet):
bound_ticket = Ticket.objects.get(token=upload_token) bound_ticket = Ticket.objects.get(token=upload_token)
if bound_ticket.resolved: if bound_ticket.resolved:
return Response( return Response(
{'error': f'ticket {bound_ticket} already resolved'}, {'detail': f'ticket {bound_ticket} already resolved'},
status=status.HTTP_423_LOCKED status=status.HTTP_423_LOCKED
) )
if bound_ticket.attempts <= 0: if bound_ticket.attempts <= 0:
return Response( return Response(
{'error': f'token {upload_token} expired'}, {'detail': f'token {upload_token} expired'},
status=status.HTTP_423_LOCKED status=status.HTTP_423_LOCKED
) )
bound_ticket.attempts -= 1 bound_ticket.attempts -= 1
bound_ticket.save() bound_ticket.save()
# ? mixin bound ticket number to request.data from user # ? mixin bound ticket number to request.data from user
request.data['ticket'] = bound_ticket.number try:
request.data['ticket'] = bound_ticket.number
except AttributeError:
return Response(
{'detail': 'Bad Request'},
status=status.HTTP_400_BAD_REQUEST
)
# ? change serializer for guest user # ? change serializer for guest user
if not request.user.is_authenticated: if not request.user.is_authenticated:
self.serializer_class = PublicArchiveUploadSerializer self.serializer_class = PublicArchiveUploadSerializer
except (ValidationError, ObjectDoesNotExist,): except (ValidationError, ObjectDoesNotExist,):
return Response( return Response(
{'error': f'token {upload_token} is not valid'}, {'detail': f'token {upload_token} is not valid'},
status=status.HTTP_403_FORBIDDEN status=status.HTTP_403_FORBIDDEN
) )
else: else:
return Response( return Response(
{'error': 'Header Upload-Token is required'}, {'detail': 'Header Upload-Token is required'},
status=status.HTTP_401_UNAUTHORIZED status=status.HTTP_401_UNAUTHORIZED
) )
# ! default create method: # ! default create method:

View File

@ -0,0 +1,24 @@
from django.http import HttpResponse
from django.template import loader
class HttpResponseNotAllowedMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
if response.status_code == 405:
context = {}
template = loader.get_template('405.html')
return HttpResponse(template.render(context, request))
return response

View File

@ -54,7 +54,6 @@ $(function () {
} }
}, },
success: function(data, textStatus, jqXHR){ success: function(data, textStatus, jqXHR){
console.log(jqXHR.status);
alertContainer.innerHTML = genAlertMessage( alertContainer.innerHTML = genAlertMessage(
'The file has been successfully uploaded to the server. Thank you!', 'The file has been successfully uploaded to the server. Thank you!',
'success', 'success',
@ -69,13 +68,15 @@ $(function () {
}; };
}, },
error: function(jqXHR, textStatus, errorThrown){ error: function(jqXHR, textStatus, errorThrown){
console.log(jqXHR);
let errorMessage = "Unexpected error. Try again please" let errorMessage = "Unexpected error. Try again please"
if (jqXHR.status === 423 || jqXHR.status === 403) { if (jqXHR.status === 423 || jqXHR.status === 403) {
errorMessage = `Error ${jqXHR.status}: ${jqXHR.responseJSON.error}` errorMessage = `Error ${jqXHR.status} <br> ${jqXHR.responseJSON.detail}`
} }
if (jqXHR.status === 401) { if (jqXHR.status === 401) {
errorMessage = 'The token field cannot be empty' errorMessage = `Error ${jqXHR.status} <br> The token field cannot be empty`
}
if (jqXHR.status === 400) {
errorMessage = `Error ${jqXHR.status} <br> ${jqXHR.responseJSON.detail}`
} }
alertContainer.innerHTML = genAlertMessage( alertContainer.innerHTML = genAlertMessage(
errorMessage, errorMessage,
@ -97,14 +98,14 @@ $(function () {
success: function (data, textStatus, jqXHR) { success: function (data, textStatus, jqXHR) {
if (data.attempts === 0) { if (data.attempts === 0) {
alertContainer.innerHTML = genAlertMessage( alertContainer.innerHTML = genAlertMessage(
`Token: ${uploadToken} expired`, `Error 423 <br> Token: ${uploadToken} expired`,
'danger', 'danger',
'col-lg-6' 'col-lg-6'
); );
} }
else if (data.resolved === true) { else if (data.resolved === true) {
alertContainer.innerHTML = genAlertMessage( alertContainer.innerHTML = genAlertMessage(
`Ticket bound with token: ${uploadToken} <br> already resolved`, `Error 423 <br> Ticket bound with token: ${uploadToken} <br> already resolved`,
'danger', 'danger',
'col-lg-6' 'col-lg-6'
); );
@ -118,11 +119,9 @@ $(function () {
}; };
}, },
error: function(jqXHR){ error: function(jqXHR){
console.log(jqXHR)
console.log(jqXHR.responseJSON.detail)
if (jqXHR.responseJSON.detail) { if (jqXHR.responseJSON.detail) {
alertContainer.innerHTML = genAlertMessage( alertContainer.innerHTML = genAlertMessage(
`Token: ${uploadToken} is not valid`, `Error 403 <br> Token: ${uploadToken} is not valid`,
'danger', 'danger',
'col-lg-6' 'col-lg-6'
) )

View File

@ -1,5 +1,5 @@
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import FileResponse from django.http import FileResponse, Http404
from django.views import generic from django.views import generic
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from django.db.models import Q from django.db.models import Q
@ -35,6 +35,10 @@ class ArchiveHandlerView(
def get(self, request, path): def get(self, request, path):
self.object = self.get_object() self.object = self.get_object()
try:
self.object.file.size
except FileNotFoundError:
raise Http404(f'File: {self.object.file} not found')
return FileResponse(self.object.file) return FileResponse(self.object.file)

View File

@ -89,6 +89,7 @@ MIDDLEWARE = [
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware',
'collector.middleware.HttpResponseNotAllowedMiddleware',
] ]
ROOT_URLCONF = 'logs_collector.urls' ROOT_URLCONF = 'logs_collector.urls'

View File

@ -0,0 +1,10 @@
{% extends 'errors.html' %}
{% load static %}
{% block title %} Logs Collector - CSRF error {% endblock title %}
{% block status_code %}403{% endblock status_code %}
{% block error_message %}
<p class="fs-3"> <span class="text-danger">Opps!</span> CSRF verification failed.</p>
<p class="lead">Request aborted</p>
{% endblock error_message %}

View File

@ -0,0 +1,10 @@
{% extends 'errors.html' %}
{% load static %}
{% block title %} Logs Collector - Not Found {% endblock title %}
{% block status_code %}404{% endblock status_code %}
{% block error_message %}
<p class="fs-3"> <span class="text-danger">Opps!</span> Page not found.</p>
<p class="lead">The content you're looking for doesn't exist.</p>
{% endblock error_message %}

View File

@ -0,0 +1,14 @@
{% extends 'errors.html' %}
{% load static %}
{% block title %} Logs Collector - Method not allowed {% endblock title %}
{% block status_code %}405{% endblock status_code %}
{% block error_message %}
<p class="fs-3"> <span class="text-danger">Opps!</span> Method not allowed</p>
<p class="lead">
Request method:
<span class="text-danger">{{ request.method }}</span>
isn't allowed for this URL
</p>
{% endblock error_message %}

View File

@ -0,0 +1,10 @@
{% extends 'errors.html' %}
{% load static %}
{% block title %} Logs Collector - Server error {% endblock title %}
{% block status_code %}500{% endblock status_code %}
{% block error_message %}
<p class="fs-3"> <span class="text-danger">Opps!</span> Server error</p>
<p class="lead">Unexpected error, please try again or contact system admin </p>
{% endblock error_message %}

View File

@ -34,10 +34,12 @@
rel="stylesheet" rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css"
> >
{% block errors_head %}{% endblock errors_head %}
{% block collector_head %}{% endblock collector_head %} {% block collector_head %}{% endblock collector_head %}
{% block account_head %}{% endblock account_head %} {% block account_head %}{% endblock account_head %}
</head> </head>
<body class="d-flex flex-column min-vh-100"> <body class="d-flex flex-column min-vh-100">
{% block http_errors %}{% endblock http_errors %}
{% block collector_content %}{% endblock collector_content %} {% block collector_content %}{% endblock collector_content %}
{% block account_content %}{% endblock account_content %} {% block account_content %}{% endblock account_content %}
<!-- BS dependences JS--> <!-- BS dependences JS-->

View File

@ -0,0 +1,20 @@
{% extends 'base.html' %}
{% load static %}
{% block errors_head %}
<title>{% block title %}{% endblock title %}</title>
{% endblock errors_head %}
{% block http_errors %}
<div class="d-flex align-items-center justify-content-center vh-100" >
<div class="text-center">
<h1 class="display-1 fw-bold">{% block status_code %}{% endblock status_code %}</h1>
{% block error_message %}{% endblock error_message %}
<a href="{% url 'collector:index' %}" class="btn btn-secondary">Go Home</a>
</div>
<!-- Theme switcher -->
<div class="dropdown position-fixed bottom-0 end-0 mb-3 me-3 bd-mode-toggle">
{% include 'includes/theme_switcher.html' %}
</div>
</div>
{% endblock http_errors %}

View File

@ -1,21 +1,29 @@
<nav class="navbar navbar-expand-lg bg-body-tertiary"> <nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container d-flex justify-content-between"> <div class="container">
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<span class="text-muted"> <button class="btn">
v{{ version }} v{{ version }}
{% if environment != 'Production' %} {% if environment != 'Production' %}
Staging: {{ environment }} Staging: {{ environment }}
{% endif %} {% endif %}
| © {{ author }} </button>
</span> </li>
<!-- Separator -->
<li class="nav-item py-2 py-lg-1 col-12 col-lg-auto">
<div class="vr d-none d-lg-flex h-100 mx-lg-2 text-white"></div>
<hr class="d-lg-none my-2 text-white-50">
</li>
<li class="nav-item">
<button class='btn'> © {{ author }} </button>
</li> </li>
</ul> </ul>
{% if request.user.is_authenticated %}
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<li> <li>
<a <a
class="nav-link" class="btn"
type="button" type="button"
href="{% url 'swagger-ui' %}" href="{% url 'swagger-ui' %}"
target="_blank" target="_blank"
@ -28,5 +36,6 @@
</a> </a>
</li> </li>
</ul> </ul>
{% endif %}
</div> </div>
</nav> </nav>