diff --git a/sage_validation/accounts/urls.py b/sage_validation/accounts/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..d2b6eada72dd075d384255e9b6bc90975172bc96 --- /dev/null +++ b/sage_validation/accounts/urls.py @@ -0,0 +1,7 @@ +"""URL configuration for the accounts' app.""" +from django.contrib.auth.views import LogoutView +from django.urls import path + +urlpatterns = [ + path("logout/", LogoutView.as_view(), name="logout"), +] diff --git a/sage_validation/file_validator/templates/upload.html b/sage_validation/file_validator/templates/upload.html index ec8619dd40130d1555c59dc7a549c6c359c57edc..a9428905a06c54a7c936c2d18c6bcddee3c6d32a 100644 --- a/sage_validation/file_validator/templates/upload.html +++ b/sage_validation/file_validator/templates/upload.html @@ -77,19 +77,32 @@ successSection.classList.remove('hidden'); downloadLink.href = result.download_url; downloadSection.classList.remove('hidden'); - } else if (response.status === 400 && result.status === 'error') { - for (const [field, messages] of Object.entries(result.errors)) { - messages.forEach(message => { - const li = document.createElement('li'); - li.textContent = `${field}: ${message}`; - errorList.appendChild(li); - }); + } else { + errorList.innerHTML = ''; + + if (response.status === 403) { + const li = document.createElement('li'); + li.textContent = 'You are not authorized to perform this action.'; + errorList.appendChild(li); + } else if (response.status === 400 && result.status === 'error') { + for (const [field, messages] of Object.entries(result.errors)) { + messages.forEach(message => { + const li = document.createElement('li'); + li.textContent = `${field}: ${message}`; + errorList.appendChild(li); + }); + } + } else { + const li = document.createElement('li'); + li.textContent = 'An unexpected error occurred. Please try again.'; + errorList.appendChild(li); } + errorSection.classList.remove('hidden'); } } catch (error) { const li = document.createElement('li'); - li.textContent = 'An unexpected error occurred. Please try again.'; + li.textContent = 'Failed to connect to the server. Please check your internet connection.'; errorList.appendChild(li); errorSection.classList.remove('hidden'); } diff --git a/sage_validation/file_validator/views.py b/sage_validation/file_validator/views.py index 9bea9c62dbbe4097776cb983ae8c3fdf94ea9b4a..a041fbc9320d00dbeb8826c7150ddf95358ff5a0 100644 --- a/sage_validation/file_validator/views.py +++ b/sage_validation/file_validator/views.py @@ -1,6 +1,7 @@ """Views for the file_validator app.""" import csv import io +from typing import ClassVar from django.http import HttpRequest, HttpResponse from django.shortcuts import render @@ -29,7 +30,8 @@ def upload_page_view(request: HttpRequest) -> HttpResponse: class CSVUploadAPIView(APIView): """API view for uploading a CSV file.""" - permission_classes = [IsAuthenticated] + + permission_classes: ClassVar[list] = [IsAuthenticated] def post(self, request: Request) -> Response: """Handle CSV upload and validation.""" diff --git a/sage_validation/settings.py b/sage_validation/settings.py index dea87dfa91892f806ec417b7d6a81d138a115ee5..2b9bf7d4ac591bfea2250696e85ca85f30c8c130 100644 --- a/sage_validation/settings.py +++ b/sage_validation/settings.py @@ -167,4 +167,4 @@ SOCIAL_AUTH_GOOGLE_OAUTH2_REDIRECT_URI = "http://localhost:8000/complete/google- SOCIAL_AUTH_JSONFIELD_ENABLED = True SOCIAL_AUTH_URL_NAMESPACE = 'social' LOGIN_REDIRECT_URL = "/" -SOCIAL_AUTH_ALLOW_DISCONNECT = True \ No newline at end of file +LOGOUT_REDIRECT_URL = "/" \ No newline at end of file diff --git a/sage_validation/templates/base.html b/sage_validation/templates/base.html index 38f87f469a4eef03fc6c3e6485c877e00e6d3420..71daa8e5dee039043a047c18e787b54780444c5f 100644 --- a/sage_validation/templates/base.html +++ b/sage_validation/templates/base.html @@ -20,11 +20,13 @@ <div class="flex items-center"> <!-- Login link --> {% if user.is_authenticated %} <p class="text-white">Welcome, {{ user.username }}!</p> - {# <a href="{% url 'social:disconnect' 'google-oauth2' %}" class="text-white hover:text-gray-300">Logout</a>#} -{# <form action="{% url 'social:disconnect' 'google-oauth2' %}" method="post">#} -{# {% csrf_token %}#} -{# <button type="submit">Logout</button>#} -{# </form>#} + <form action="{% url 'logout' %}" method="post" class="inline-block ml-4"> + {% csrf_token %} + <button type="submit" + class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 focus:outline-none focus:ring focus:ring-red-400"> + Logout + </button> + </form> {% else %} <a href="{% url "social:begin" "google-oauth2" %}" class="text-white hover:text-gray-300">Login</a> {% endif %} diff --git a/sage_validation/urls.py b/sage_validation/urls.py index f839b99fab7178d94eebbc22b43e4d2306dd9db3..1146896db11939a8c6ddc3db541093f717b62166 100644 --- a/sage_validation/urls.py +++ b/sage_validation/urls.py @@ -9,6 +9,6 @@ urlpatterns = [ path("admin/", admin.site.urls), path("file-validator/", include("sage_validation.file_validator.urls")), path("", index_view, name="index"), - path("", include("social_django.urls", namespace="social")) - + path("", include("social_django.urls", namespace="social")), + path("accounts/", include("sage_validation.accounts.urls")), ]