From 192116f711b99a7cd4ab5345d5921f26e3f2bb15 Mon Sep 17 00:00:00 2001 From: Xavier Fernandez Date: Thu, 28 Nov 2024 11:53:40 +0100 Subject: [PATCH 1/4] settings: add LoginRequiredMiddleware --- config/settings/base.py | 1 + config/urls.py | 27 +++++++++++++++---- itou/api/applicants_api/views.py | 3 ++- itou/api/c4_api/views.py | 3 ++- itou/api/data_inclusion_api/views.py | 3 ++- itou/api/employee_record_api/viewsets.py | 3 ++- itou/api/geiq/views.py | 3 ++- itou/api/redoc_views.py | 4 ++- itou/api/siae_api/viewsets.py | 3 ++- itou/api/token_auth/views.py | 3 ++- itou/api/urls.py | 3 ++- itou/openid_connect/france_connect/views.py | 4 +++ .../openid_connect/inclusion_connect/views.py | 5 ++++ itou/openid_connect/pe_connect/views.py | 5 ++++ itou/openid_connect/pro_connect/views.py | 5 ++++ itou/status/views.py | 2 ++ itou/utils/auth.py | 8 ++++++ itou/utils/redirect_legacy_views.py | 2 ++ itou/www/announcements/views.py | 3 ++- itou/www/api/urls.py | 3 ++- itou/www/autocomplete/views.py | 5 +++- itou/www/companies_views/views.py | 9 ++++--- itou/www/error.py | 2 ++ itou/www/home/views.py | 2 ++ itou/www/invitations_views/views.py | 3 ++- itou/www/login/views.py | 3 ++- itou/www/prescribers_views/views.py | 3 ++- itou/www/rdv_insertion/views.py | 2 ++ itou/www/releases/views.py | 2 ++ itou/www/search/views.py | 7 ++++- itou/www/security/views.py | 2 ++ itou/www/siae_evaluations_views/views.py | 3 ++- itou/www/signup/urls.py | 3 ++- itou/www/signup/views.py | 27 ++++++++++++++----- itou/www/stats/views.py | 3 ++- tests/www/apply/test_submit.py | 12 ++++----- tests/www/signup/test_prescriber.py | 7 ++++- 37 files changed, 148 insertions(+), 40 deletions(-) diff --git a/config/settings/base.py b/config/settings/base.py index 8ee1c245c8..d681d5e2d6 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -134,6 +134,7 @@ "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.auth.middleware.LoginRequiredMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", # Third party diff --git a/config/urls.py b/config/urls.py index 4b14c0def6..a9966568be 100644 --- a/config/urls.py +++ b/config/urls.py @@ -1,6 +1,7 @@ from anymail.webhooks.mailjet import MailjetTrackingWebhookView from django.conf import settings from django.contrib import admin +from django.contrib.auth.decorators import login_not_required from django.urls import include, path, re_path, register_converter from django.views.generic import TemplateView @@ -88,13 +89,29 @@ path("versions/", include("itou.www.releases.urls")), # Enable Mailjet status tracking # https://anymail.readthedocs.io/en/stable/esps/mailjet/#status-tracking-webhooks - path("webhooks/anymail/mailjet/tracking/", MailjetTrackingWebhookView.as_view()), + path("webhooks/anymail/mailjet/tracking/", login_not_required(MailjetTrackingWebhookView.as_view())), path("welcoming_tour/", include("itou.www.welcoming_tour.urls")), # Static pages. - path("accessibility/", TemplateView.as_view(template_name="static/accessibility.html"), name="accessibility"), - path("legal/notice/", TemplateView.as_view(template_name="static/legal/notice.html"), name="legal-notice"), - path("legal/privacy/", TemplateView.as_view(template_name="static/legal/privacy.html"), name="legal-privacy"), - path("legal/terms/", TemplateView.as_view(template_name="static/legal/terms.html"), name="legal-terms"), + path( + "accessibility/", + login_not_required(TemplateView.as_view(template_name="static/accessibility.html")), + name="accessibility", + ), + path( + "legal/notice/", + login_not_required(TemplateView.as_view(template_name="static/legal/notice.html")), + name="legal-notice", + ), + path( + "legal/privacy/", + login_not_required(TemplateView.as_view(template_name="static/legal/privacy.html")), + name="legal-privacy", + ), + path( + "legal/terms/", + login_not_required(TemplateView.as_view(template_name="static/legal/terms.html")), + name="legal-terms", + ), path("", include("itou.www.security.urls")), path("gps/", include("itou.www.gps.urls")), path("rdvi/", include("itou.www.rdv_insertion.urls")), diff --git a/itou/api/applicants_api/views.py b/itou/api/applicants_api/views.py index b6affaa105..6cc22ee675 100644 --- a/itou/api/applicants_api/views.py +++ b/itou/api/applicants_api/views.py @@ -8,12 +8,13 @@ from itou.job_applications.models import JobApplication from itou.users.enums import UserKind from itou.users.models import User +from itou.utils.auth import LoginNotRequiredMixin from .perms import ApplicantsAPIPermission from .serializers import APIParametersSerializer, ApplicantSerializer -class ApplicantsView(generics.ListAPIView): +class ApplicantsView(LoginNotRequiredMixin, generics.ListAPIView): authentication_classes = ( authentication.TokenAuthentication, authentication.SessionAuthentication, diff --git a/itou/api/c4_api/views.py b/itou/api/c4_api/views.py index ba3c8626cd..ae2be20b0e 100644 --- a/itou/api/c4_api/views.py +++ b/itou/api/c4_api/views.py @@ -6,6 +6,7 @@ from itou.api.c4_api.serializers import C4CompanySerializer from itou.companies.enums import COMPANY_KIND_RESERVED from itou.companies.models import Company, CompanyMembership +from itou.utils.auth import LoginNotRequiredMixin class C4APIUser(AnonymousUser): @@ -27,7 +28,7 @@ def authenticate_credentials(self, key): return C4APIUser(), None -class C4CompanyView(generics.ListAPIView): +class C4CompanyView(LoginNotRequiredMixin, generics.ListAPIView): """API pour le Marché de l'inclusion""" authentication_classes = [C4Authentication] diff --git a/itou/api/data_inclusion_api/views.py b/itou/api/data_inclusion_api/views.py index 7d7f0da556..5e144007c2 100644 --- a/itou/api/data_inclusion_api/views.py +++ b/itou/api/data_inclusion_api/views.py @@ -5,6 +5,7 @@ from itou.api.data_inclusion_api import enums, serializers from itou.companies.models import Company from itou.prescribers.models import PrescriberOrganization +from itou.utils.auth import LoginNotRequiredMixin @extend_schema( @@ -18,7 +19,7 @@ many=True, ) ) -class DataInclusionStructureView(generics.ListAPIView): +class DataInclusionStructureView(LoginNotRequiredMixin, generics.ListAPIView): """ # API au format data.inclusion diff --git a/itou/api/employee_record_api/viewsets.py b/itou/api/employee_record_api/viewsets.py index 84e9b60170..aaef9d99a8 100644 --- a/itou/api/employee_record_api/viewsets.py +++ b/itou/api/employee_record_api/viewsets.py @@ -8,6 +8,7 @@ from itou.api import AUTH_TOKEN_EXPLANATION_TEXT from itou.employee_record.models import EmployeeRecord, EmployeeRecordUpdateNotification, Status +from itou.utils.auth import LoginNotRequiredMixin from .perms import EmployeeRecordAPIPermission from .serializers import EmployeeRecordAPISerializer, EmployeeRecordUpdateNotificationAPISerializer @@ -22,7 +23,7 @@ class EmployeeRecordRateThrottle(UserRateThrottle): rate = "60/min" -class AbstractEmployeeRecordViewSet(viewsets.ReadOnlyModelViewSet): +class AbstractEmployeeRecordViewSet(LoginNotRequiredMixin, viewsets.ReadOnlyModelViewSet): throttle_classes = [EmployeeRecordRateThrottle] # Possible authentication frameworks: diff --git a/itou/api/geiq/views.py b/itou/api/geiq/views.py index c9da50a1e1..54b991d990 100644 --- a/itou/api/geiq/views.py +++ b/itou/api/geiq/views.py @@ -10,6 +10,7 @@ from itou.companies.models import Company from itou.job_applications.enums import JobApplicationState, Prequalification, ProfessionalSituationExperience from itou.job_applications.models import JobApplication, PriorAction +from itou.utils.auth import LoginNotRequiredMixin from itou.utils.validators import validate_siren from .serializers import GeiqJobApplicationSerializer @@ -41,7 +42,7 @@ class InvalidSirenError(exceptions.APIException): status_code = status.HTTP_400_BAD_REQUEST -class GeiqJobApplicationListView(generics.ListAPIView): +class GeiqJobApplicationListView(LoginNotRequiredMixin, generics.ListAPIView): authentication_classes = ( GeiqApiAuthentication, authentication.SessionAuthentication, diff --git a/itou/api/redoc_views.py b/itou/api/redoc_views.py index dc6707d791..e3464885b7 100644 --- a/itou/api/redoc_views.py +++ b/itou/api/redoc_views.py @@ -1,8 +1,10 @@ from django.templatetags.static import static from drf_spectacular.views import SpectacularRedocView +from itou.utils.auth import LoginNotRequiredMixin -class ItouSpectacularRedocView(SpectacularRedocView): + +class ItouSpectacularRedocView(LoginNotRequiredMixin, SpectacularRedocView): @staticmethod def _redoc_standalone(): return static("vendor/redoc/redoc.standalone.js") diff --git a/itou/api/siae_api/viewsets.py b/itou/api/siae_api/viewsets.py index 43a8f431bf..b4817f309c 100644 --- a/itou/api/siae_api/viewsets.py +++ b/itou/api/siae_api/viewsets.py @@ -14,6 +14,7 @@ from itou.cities.models import City from itou.common_apps.address.departments import DEPARTMENTS from itou.companies.models import Company, JobDescription +from itou.utils.auth import LoginNotRequiredMixin from .serializers import SiaeSerializer @@ -119,7 +120,7 @@ class RestrictedUserRateThrottle(UserRateThrottle): rate = "12/minute" -class SiaeViewSet(viewsets.ReadOnlyModelViewSet): +class SiaeViewSet(LoginNotRequiredMixin, viewsets.ReadOnlyModelViewSet): """ # Liste des SIAE diff --git a/itou/api/token_auth/views.py b/itou/api/token_auth/views.py index 5ef3cc8167..166c29831c 100644 --- a/itou/api/token_auth/views.py +++ b/itou/api/token_auth/views.py @@ -6,6 +6,7 @@ from rest_framework.response import Response from itou.api import AUTH_TOKEN_EXPLANATION_TEXT +from itou.utils.auth import LoginNotRequiredMixin logger = logging.getLogger(__name__) @@ -14,7 +15,7 @@ TOKEN_ID_STR = "__token__" -class ObtainAuthToken(drf_authtoken_views.ObtainAuthToken): +class ObtainAuthToken(LoginNotRequiredMixin, drf_authtoken_views.ObtainAuthToken): def post(self, request, *args, **kwargs): if request.data.get("username") == TOKEN_ID_STR: password = request.data.get("password") diff --git a/itou/api/urls.py b/itou/api/urls.py index d8fd9682f6..ad2d469338 100644 --- a/itou/api/urls.py +++ b/itou/api/urls.py @@ -1,3 +1,4 @@ +from django.contrib.auth.decorators import login_not_required from django.urls import include, path from drf_spectacular.views import SpectacularAPIView from rest_framework import routers @@ -41,7 +42,7 @@ # OAS 3 YAML schema (downloadable) path( "oas3/", - SpectacularAPIView.as_view(), + login_not_required(SpectacularAPIView.as_view()), name="openapi_schema", ), path( diff --git a/itou/openid_connect/france_connect/views.py b/itou/openid_connect/france_connect/views.py index 0d87e15794..26cac95477 100644 --- a/itou/openid_connect/france_connect/views.py +++ b/itou/openid_connect/france_connect/views.py @@ -5,6 +5,7 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth import login +from django.contrib.auth.decorators import login_not_required from django.http import HttpResponseRedirect, JsonResponse from django.urls import reverse from django.utils import crypto @@ -35,6 +36,7 @@ def _redirect_to_job_seeker_login_on_error(error_msg, request=None, extra_tags=" return HttpResponseRedirect(reverse("login:job_seeker")) +@login_not_required def france_connect_authorize(request): # The redirect_uri should be defined in the FC settings to be allowed # NB: the integration platform allows "http://127.0.0.1:8000/franceconnect/callback" @@ -53,6 +55,7 @@ def france_connect_authorize(request): return HttpResponseRedirect(f"{url}?{urlencode(data)}") +@login_not_required def france_connect_callback(request): code = request.GET.get("code") if code is None: @@ -157,6 +160,7 @@ def france_connect_callback(request): return HttpResponseRedirect(next_url) +@login_not_required def france_connect_logout(request): # The user can be authentified on FC w/o a session on itou. # https://partenaires.franceconnect.gouv.fr/fcp/fournisseur-service#sign_out diff --git a/itou/openid_connect/inclusion_connect/views.py b/itou/openid_connect/inclusion_connect/views.py index 885371f93f..6e913448a1 100644 --- a/itou/openid_connect/inclusion_connect/views.py +++ b/itou/openid_connect/inclusion_connect/views.py @@ -6,6 +6,7 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth import login +from django.contrib.auth.decorators import login_not_required from django.http import HttpResponseRedirect from django.urls import reverse from django.utils import crypto @@ -120,6 +121,7 @@ def _add_user_kind_error_message(request, existing_user, new_user_kind): ) +@login_not_required def inclusion_connect_authorize(request): # Block access if ProConnect is enabled if settings.PRO_CONNECT_BASE_URL: @@ -166,6 +168,7 @@ def inclusion_connect_authorize(request): return HttpResponseRedirect(f"{base_url}?{urlencode(data)}") +@login_not_required def inclusion_connect_activate_account(request): params = request.GET.copy() email = params.get("user_email") @@ -228,6 +231,7 @@ def _get_user_info(request, access_token): return response.json(), None +@login_not_required def inclusion_connect_callback(request): # Block access if ProConnect is enabled if settings.PRO_CONNECT_BASE_URL: @@ -356,6 +360,7 @@ def inclusion_connect_callback(request): return HttpResponseRedirect(next_url) +@login_not_required def inclusion_connect_logout(request): token = request.GET.get("token") post_logout_redirect_url = request.GET.get("redirect_url", reverse("search:employers_home")) diff --git a/itou/openid_connect/pe_connect/views.py b/itou/openid_connect/pe_connect/views.py index 14e149d345..0446410cac 100644 --- a/itou/openid_connect/pe_connect/views.py +++ b/itou/openid_connect/pe_connect/views.py @@ -5,6 +5,7 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth import login +from django.contrib.auth.decorators import login_not_required from django.http import HttpResponseRedirect, JsonResponse from django.shortcuts import render from django.urls import reverse @@ -39,6 +40,7 @@ def _redirect_to_job_seeker_login_on_error(error_msg, request=None, extra_tags=" return HttpResponseRedirect(reverse("login:job_seeker")) +@login_not_required def pe_connect_authorize(request): # The redirect_uri should be defined in the PEAMU settings to be allowed # NB: the integration platform allows "http://127.0.0.1:8000/pe_connect/callback" @@ -57,6 +59,7 @@ def pe_connect_authorize(request): return HttpResponseRedirect(f"{url}?{urlencode(data)}") +@login_not_required def pe_connect_callback(request): code = request.GET.get("code") if code is None: @@ -180,10 +183,12 @@ def pe_connect_callback(request): return HttpResponseRedirect(next_url) +@login_not_required def pe_connect_no_email(request, template_name="account/peamu_no_email.html"): return render(request, template_name) +@login_not_required def pe_connect_logout(request): id_token = request.GET.get("id_token") diff --git a/itou/openid_connect/pro_connect/views.py b/itou/openid_connect/pro_connect/views.py index 3278c686cb..fcedb8b3f9 100644 --- a/itou/openid_connect/pro_connect/views.py +++ b/itou/openid_connect/pro_connect/views.py @@ -7,6 +7,7 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth import login +from django.contrib.auth.decorators import login_not_required from django.http import HttpResponseRedirect from django.urls import reverse from django.utils import crypto @@ -109,6 +110,7 @@ def _add_user_kind_error_message(request, existing_user, new_user_kind): ) +@login_not_required def pro_connect_authorize(request): # Start a new session. user_kind = request.GET.get("user_kind") @@ -185,6 +187,7 @@ def _get_user_info(request, access_token): return decoded_id_token, None +@login_not_required def pro_connect_callback(request): code = request.GET.get("code") state = request.GET.get("state") @@ -307,6 +310,7 @@ def pro_connect_callback(request): return HttpResponseRedirect(next_url) +@login_not_required def pro_connect_logout(request): token = request.GET.get("token") post_logout_redirect_url = reverse("pro_connect:logout_callback") @@ -330,6 +334,7 @@ def pro_connect_logout(request): return HttpResponseRedirect(complete_url) +@login_not_required def pro_connect_logout_callback(request): state = request.GET.get("state") if state is None: diff --git a/itou/status/views.py b/itou/status/views.py index 782b20b587..8022b4ac21 100644 --- a/itou/status/views.py +++ b/itou/status/views.py @@ -1,8 +1,10 @@ +from django.contrib.auth.decorators import login_not_required from django.shortcuts import render from . import models, probes +@login_not_required def index(request): probes_classes = sorted(probes.get_probes_classes(), key=lambda p: p.name) probes_status_by_name = {ps.name: ps for ps in models.ProbeStatus.objects.all()} diff --git a/itou/utils/auth.py b/itou/utils/auth.py index 5458e57fb3..189385755d 100644 --- a/itou/utils/auth.py +++ b/itou/utils/auth.py @@ -1,5 +1,6 @@ from functools import wraps +from django.contrib.auth.decorators import login_not_required from django.core.exceptions import PermissionDenied @@ -15,3 +16,10 @@ def _check_user_view_wrapper(request, *args, **kwargs): return wraps(view_func)(_check_user_view_wrapper) return decorator + + +class LoginNotRequiredMixin: + @classmethod + def as_view(cls, *args, **kwargs): + view = super().as_view(*args, **kwargs) + return login_not_required(view) diff --git a/itou/utils/redirect_legacy_views.py b/itou/utils/redirect_legacy_views.py index e592ca6040..9715520306 100644 --- a/itou/utils/redirect_legacy_views.py +++ b/itou/utils/redirect_legacy_views.py @@ -1,5 +1,7 @@ +from django.contrib.auth.decorators import login_not_required from django.http import HttpResponsePermanentRedirect +@login_not_required def redirect_siaes_views(request, *args, **kwargs): return HttpResponsePermanentRedirect(request.get_full_path().replace("/siae", "/company", 1)) diff --git a/itou/www/announcements/views.py b/itou/www/announcements/views.py index f62a5838b5..ad16d5f8ff 100644 --- a/itou/www/announcements/views.py +++ b/itou/www/announcements/views.py @@ -5,11 +5,12 @@ from itou.communications.models import AnnouncementCampaign, AnnouncementItem from itou.users.enums import UserKind +from itou.utils.auth import LoginNotRequiredMixin from itou.utils.pagination import pager from itou.utils.urls import get_safe_url -class NewsView(TemplateView): +class NewsView(LoginNotRequiredMixin, TemplateView): template_name = "announcements/news.html" def get_context_data(self): diff --git a/itou/www/api/urls.py b/itou/www/api/urls.py index 06441fcf8a..d8e369348f 100644 --- a/itou/www/api/urls.py +++ b/itou/www/api/urls.py @@ -1,3 +1,4 @@ +from django.contrib.auth.decorators import login_not_required from django.urls import path from django.views.generic import TemplateView @@ -6,5 +7,5 @@ urlpatterns = [ - path("", TemplateView.as_view(template_name="api/index.html"), name="index"), + path("", login_not_required(TemplateView.as_view(template_name="api/index.html")), name="index"), ] diff --git a/itou/www/autocomplete/views.py b/itou/www/autocomplete/views.py index 80afe4bc31..a27081e9c7 100644 --- a/itou/www/autocomplete/views.py +++ b/itou/www/autocomplete/views.py @@ -1,6 +1,6 @@ from datetime import datetime -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_not_required, login_required from django.db.models import F, Q, Value from django.db.models.functions import Least, Lower, NullIf, StrIndex from django.http import JsonResponse @@ -43,6 +43,7 @@ def autocomplete_name(qs, term, extra_ordering_by): ) +@login_not_required def cities_autocomplete(request): """ Returns JSON data compliant with Select2 @@ -66,6 +67,7 @@ def cities_autocomplete(request): return JsonResponse({"results": cities}, safe=False) +@login_not_required def jobs_autocomplete(request): """ Returns JSON data compliant with Select2 @@ -86,6 +88,7 @@ def jobs_autocomplete(request): return JsonResponse({"results": appellations}, safe=False) +@login_not_required def communes_autocomplete(request): """ Autocomplete endpoint for INSEE communes (ASP ref. files) diff --git a/itou/www/companies_views/views.py b/itou/www/companies_views/views.py index dd4929ea9f..9b1efa4dcf 100644 --- a/itou/www/companies_views/views.py +++ b/itou/www/companies_views/views.py @@ -3,7 +3,7 @@ from django.conf import settings from django.contrib import messages -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_not_required, login_required from django.core.cache import caches from django.core.exceptions import PermissionDenied from django.db.models import Count, Q @@ -23,6 +23,7 @@ from itou.utils import constants as global_constants from itou.utils.apis.data_inclusion import DataInclusionApiClient, DataInclusionApiException from itou.utils.apis.exceptions import GeocodingDataError +from itou.utils.auth import LoginNotRequiredMixin from itou.utils.pagination import pager from itou.utils.perms.company import get_current_company_or_404 from itou.utils.urls import add_url_params, get_absolute_url, get_safe_url @@ -123,7 +124,7 @@ def overview(request, template_name="companies/overview.html"): ### Job description views -class JobDescriptionCardView(ApplyForJobSeekerMixin, TemplateView): +class JobDescriptionCardView(LoginNotRequiredMixin, ApplyForJobSeekerMixin, TemplateView): template_name = "companies/job_description_card.html" def setup(self, request, job_description_id, *args, **kwargs): @@ -459,7 +460,7 @@ def select_financial_annex(request, template_name="companies/select_financial_an ### Company CRUD views -class CompanyCardView(ApplyForJobSeekerMixin, TemplateView): +class CompanyCardView(LoginNotRequiredMixin, ApplyForJobSeekerMixin, TemplateView): template_name = "companies/card.html" def setup(self, request, siae_id, *args, **kwargs): @@ -680,6 +681,7 @@ def update_admin_role(request, action, user_id, template_name="companies/update_ return render(request, template_name, context) +@login_not_required def hx_dora_services(request, code_insee, template_name="companies/hx_dora_services.html"): context = { "data_inclusion_services": get_data_inclusion_services(code_insee), @@ -688,6 +690,7 @@ def hx_dora_services(request, code_insee, template_name="companies/hx_dora_servi return render(request, template_name, context) +@login_not_required def dora_service_redirect(request, source: str, service_id: str) -> HttpResponseRedirect: client = DataInclusionApiClient( settings.API_DATA_INCLUSION_BASE_URL, diff --git a/itou/www/error.py b/itou/www/error.py index fa0de0bc4d..fd1cebb4f6 100644 --- a/itou/www/error.py +++ b/itou/www/error.py @@ -1,5 +1,6 @@ import logging +from django.contrib.auth.decorators import login_not_required from django.http import HttpResponseServerError from django.template import TemplateDoesNotExist, engines, loader from django.views.decorators.csrf import requires_csrf_token @@ -7,6 +8,7 @@ @requires_csrf_token +@login_not_required def server_error(request, template_name=ERROR_500_TEMPLATE_NAME): try: template = loader.get_template(template_name) diff --git a/itou/www/home/views.py b/itou/www/home/views.py index cf2bc002d5..c6f9406f19 100644 --- a/itou/www/home/views.py +++ b/itou/www/home/views.py @@ -1,7 +1,9 @@ +from django.contrib.auth.decorators import login_not_required from django.http import HttpResponseRedirect from django.urls import reverse +@login_not_required def home(request): if request.user.is_authenticated: return HttpResponseRedirect(reverse("dashboard:index")) diff --git a/itou/www/invitations_views/views.py b/itou/www/invitations_views/views.py index 516b30abea..740c11b910 100644 --- a/itou/www/invitations_views/views.py +++ b/itou/www/invitations_views/views.py @@ -3,7 +3,7 @@ from allauth.account.adapter import get_adapter from django.conf import settings from django.contrib import messages -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_not_required, login_required from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect, render, reverse from django.utils import formats, safestring @@ -72,6 +72,7 @@ def handle_invited_user_registration_with_inclusion_or_pro_connect(request, invi return render(request, "invitations_views/new_ic_user.html", context=context) +@login_not_required def new_user(request, invitation_type, invitation_id): if invitation_type not in [KIND_LABOR_INSPECTOR, KIND_PRESCRIBER, KIND_EMPLOYER]: messages.error(request, "Cette invitation n'est plus valide.") diff --git a/itou/www/login/views.py b/itou/www/login/views.py index b62d962181..03c4ad7dd4 100644 --- a/itou/www/login/views.py +++ b/itou/www/login/views.py @@ -10,11 +10,12 @@ from itou.openid_connect.inclusion_connect.enums import InclusionConnectChannel from itou.users.enums import MATOMO_ACCOUNT_TYPE, IdentityProvider, UserKind from itou.users.models import User +from itou.utils.auth import LoginNotRequiredMixin from itou.utils.urls import add_url_params, get_safe_url, get_url_param_value from itou.www.login.forms import ItouLoginForm -class ItouLoginView(LoginView): +class ItouLoginView(LoginNotRequiredMixin, LoginView): """ Generic authentication entry point. This view is used only in one case: diff --git a/itou/www/prescribers_views/views.py b/itou/www/prescribers_views/views.py index 7a7a2c3ce2..b712848e97 100644 --- a/itou/www/prescribers_views/views.py +++ b/itou/www/prescribers_views/views.py @@ -1,5 +1,5 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_not_required, login_required from django.core.exceptions import PermissionDenied from django.db.models import Count, Q from django.http import HttpResponseRedirect @@ -16,6 +16,7 @@ from itou.www.prescribers_views.forms import EditPrescriberOrganizationForm +@login_not_required def card(request, org_id, template_name="prescribers/card.html"): prescriber_org = get_object_or_404(PrescriberOrganization, pk=org_id, is_authorized=True) back_url = get_safe_url(request, "back_url") diff --git a/itou/www/rdv_insertion/views.py b/itou/www/rdv_insertion/views.py index dd6ea35382..9377f34a4a 100644 --- a/itou/www/rdv_insertion/views.py +++ b/itou/www/rdv_insertion/views.py @@ -5,6 +5,7 @@ import logging from django.conf import settings +from django.contrib.auth.decorators import login_not_required from django.db import transaction from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt @@ -32,6 +33,7 @@ class UnsupportedEvent(Warning): @require_POST @csrf_exempt +@login_not_required def webhook(request): try: # FIXME: RDV-I encodings should be consistent diff --git a/itou/www/releases/views.py b/itou/www/releases/views.py index 6faac7ebba..7ed49ab86a 100644 --- a/itou/www/releases/views.py +++ b/itou/www/releases/views.py @@ -2,10 +2,12 @@ import markdown from django.conf import settings +from django.contrib.auth.decorators import login_not_required from django.shortcuts import render from django.utils.html import mark_safe +@login_not_required def releases(request, template_name="releases/list.html"): """ Render our CHANGELOG.md file in HTML diff --git a/itou/www/search/views.py b/itou/www/search/views.py index 3305c26590..fe1c5156fd 100644 --- a/itou/www/search/views.py +++ b/itou/www/search/views.py @@ -1,6 +1,7 @@ from collections import defaultdict, namedtuple from urllib.parse import urlencode +from django.contrib.auth.decorators import login_not_required from django.contrib.gis.db.models.functions import Distance from django.db.models import Case, F, Prefetch, Q, When from django.shortcuts import render @@ -12,6 +13,7 @@ from itou.companies.models import Company, JobDescription from itou.job_applications.models import JobApplication, JobApplicationWorkflow from itou.prescribers.models import PrescriberOrganization +from itou.utils.auth import LoginNotRequiredMixin from itou.utils.pagination import pager from itou.utils.urls import add_url_params from itou.www.apply.views.submit_views import ApplyForJobSeekerMixin @@ -25,12 +27,13 @@ PageAndCounts = namedtuple("PageAndCounts", ("results_page", "siaes_count", "job_descriptions_count")) +@login_not_required def employer_search_home(request, template_name="search/siaes_search_home.html"): context = {"siae_search_form": SiaeSearchForm()} return render(request, template_name, context) -class EmployerSearchBaseView(ApplyForJobSeekerMixin, FormView): +class EmployerSearchBaseView(LoginNotRequiredMixin, ApplyForJobSeekerMixin, FormView): form_class = SiaeSearchForm initial = {"distance": SiaeSearchForm.DISTANCE_DEFAULT} @@ -276,6 +279,7 @@ def get_results_page_and_counts(self, siaes, job_descriptions): ) +@login_not_required def search_prescribers_home(request, template_name="search/prescribers_search_home.html"): """ The search home page has a different design from the results page. @@ -285,6 +289,7 @@ def search_prescribers_home(request, template_name="search/prescribers_search_ho return render(request, template_name, context) +@login_not_required def search_prescribers_results(request, template_name="search/prescribers_search_results.html"): city = None distance = None diff --git a/itou/www/security/views.py b/itou/www/security/views.py index ae4878babd..417e79e28b 100644 --- a/itou/www/security/views.py +++ b/itou/www/security/views.py @@ -1,5 +1,7 @@ +from django.contrib.auth.decorators import login_not_required from django.http import HttpResponseRedirect +@login_not_required def security_txt(request): return HttpResponseRedirect("https://inclusion.gouv.fr/.well-known/security.txt") diff --git a/itou/www/siae_evaluations_views/views.py b/itou/www/siae_evaluations_views/views.py index c3bae92b3a..81b3047dec 100644 --- a/itou/www/siae_evaluations_views/views.py +++ b/itou/www/siae_evaluations_views/views.py @@ -1,5 +1,5 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_not_required, login_required from django.contrib.auth.mixins import LoginRequiredMixin from django.core.files.storage import default_storage from django.db.models import Q @@ -744,5 +744,6 @@ def view_proof(request, evaluated_administrative_criteria_id): return HttpResponseRedirect(default_storage.url(criteria.proof_id)) +@login_not_required def sanctions_helper_view(request): return render(request, "siae_evaluations/sanctions_helper.html") diff --git a/itou/www/signup/urls.py b/itou/www/signup/urls.py index 09032ecd34..3492cbdaee 100644 --- a/itou/www/signup/urls.py +++ b/itou/www/signup/urls.py @@ -1,3 +1,4 @@ +from django.contrib.auth.decorators import login_not_required from django.urls import path, re_path from django.views.generic import TemplateView @@ -23,7 +24,7 @@ ), path( "job_seeker/situation_not_eligible", - TemplateView.as_view(template_name="signup/job_seeker_situation_not_eligible.html"), + login_not_required(TemplateView.as_view(template_name="signup/job_seeker_situation_not_eligible.html")), name="job_seeker_situation_not_eligible", ), path( diff --git a/itou/www/signup/views.py b/itou/www/signup/views.py index 98139aee68..036803190a 100644 --- a/itou/www/signup/views.py +++ b/itou/www/signup/views.py @@ -9,7 +9,7 @@ from django.conf import settings from django.contrib import auth, messages from django.contrib.auth import REDIRECT_FIELD_NAME, login -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_not_required, login_required from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from django.db import Error, transaction @@ -28,6 +28,7 @@ from itou.users.adapter import UserAdapter from itou.users.enums import KIND_EMPLOYER, KIND_PRESCRIBER, MATOMO_ACCOUNT_TYPE, UserKind from itou.utils import constants as global_constants +from itou.utils.auth import LoginNotRequiredMixin from itou.utils.nav_history import get_prev_url_from_history, push_url_in_history from itou.utils.tokens import company_signup_token_generator from itou.utils.urls import get_safe_url @@ -82,6 +83,7 @@ def get_success_url(self): return super().get_success_url() +@login_not_required @require_GET def signup(request, template_name="signup/signup.html"): """ @@ -94,7 +96,7 @@ def signup(request, template_name="signup/signup.html"): return render(request, template_name, context) -class ChooseUserKindSignupView(FormView): +class ChooseUserKindSignupView(LoginNotRequiredMixin, FormView): template_name = "signup/choose_user_kind.html" form_class = forms.ChooseUserKindSignupForm @@ -107,6 +109,7 @@ def form_valid(self, form): return HttpResponseRedirect(urls[form.cleaned_data["kind"]]) +@login_not_required def job_seeker_situation(request, template_name="signup/job_seeker_situation.html"): """ Second step of the signup process for jobseeker. @@ -136,6 +139,7 @@ def job_seeker_situation(request, template_name="signup/job_seeker_situation.htm return render(request, template_name, context) +@login_not_required def job_seeker_signup_info(request, template_name="signup/job_seeker_signup.html"): form_class = forms.JobSeekerSignupWithOptionalNirForm if "skip" in request.POST else forms.JobSeekerSignupForm form = form_class(data=request.POST or None) @@ -169,7 +173,7 @@ def job_seeker_signup_info(request, template_name="signup/job_seeker_signup.html return render(request, template_name, context) -class JobSeekerCredentialsSignupView(SignupView): +class JobSeekerCredentialsSignupView(LoginNotRequiredMixin, SignupView): form_class = forms.JobSeekerCredentialsSignupForm template_name = "signup/job_seeker_signup_credentials.html" @@ -200,6 +204,7 @@ def form_valid(self, form): # ------------------------------------------------------------------------------------------ +@login_not_required def company_select(request, template_name="signup/company_select.html"): """ Entry point of the signup process for SIAEs which consists of 2 steps. @@ -282,7 +287,7 @@ def dispatch(self, request, *args, company_id, **kwargs): return super().dispatch(request, *args, **kwargs) -class CompanyUserView(CompanyBaseView, TemplateView): +class CompanyUserView(LoginNotRequiredMixin, CompanyBaseView, TemplateView): """ Display Inclusion Connect button. This page is also shown if an error is detected during @@ -349,6 +354,7 @@ def decorated(request, *args, **kwargs): return decorated +@login_not_required def prescriber_check_already_exists(request, template_name="signup/prescriber_check_already_exists.html"): """ @@ -418,6 +424,7 @@ def prescriber_check_already_exists(request, template_name="signup/prescriber_ch return render(request, template_name, context) +@login_not_required @valid_prescriber_signup_session_required @push_url_in_history(global_constants.ITOU_SESSION_PRESCRIBER_SIGNUP_KEY) def prescriber_request_invitation(request, membership_id, template_name="signup/prescriber_request_invitation.html"): @@ -453,6 +460,7 @@ def prescriber_request_invitation(request, membership_id, template_name="signup/ return render(request, template_name, context) +@login_not_required @valid_prescriber_signup_session_required @push_url_in_history(global_constants.ITOU_SESSION_PRESCRIBER_SIGNUP_KEY) def prescriber_choose_org(request, siret, template_name="signup/prescriber_choose_org.html"): @@ -498,6 +506,7 @@ def prescriber_choose_org(request, siret, template_name="signup/prescriber_choos return render(request, template_name, context) +@login_not_required @valid_prescriber_signup_session_required @push_url_in_history(global_constants.ITOU_SESSION_PRESCRIBER_SIGNUP_KEY) def prescriber_choose_kind(request, template_name="signup/prescriber_choose_kind.html"): @@ -542,6 +551,7 @@ def prescriber_choose_kind(request, template_name="signup/prescriber_choose_kind return render(request, template_name, context) +@login_not_required @valid_prescriber_signup_session_required @push_url_in_history(global_constants.ITOU_SESSION_PRESCRIBER_SIGNUP_KEY) def prescriber_confirm_authorization(request, template_name="signup/prescriber_confirm_authorization.html"): @@ -576,6 +586,7 @@ def prescriber_confirm_authorization(request, template_name="signup/prescriber_c return render(request, template_name, context) +@login_not_required @valid_prescriber_signup_session_required @push_url_in_history(global_constants.ITOU_SESSION_PRESCRIBER_SIGNUP_KEY) def prescriber_pole_emploi_safir_code(request, template_name="signup/prescriber_pole_emploi_safir_code.html"): @@ -608,6 +619,7 @@ def prescriber_pole_emploi_safir_code(request, template_name="signup/prescriber_ return render(request, template_name, context) +@login_not_required @valid_prescriber_signup_session_required @push_url_in_history(global_constants.ITOU_SESSION_PRESCRIBER_SIGNUP_KEY) def prescriber_check_pe_email(request, template_name="signup/prescriber_check_pe_email.html"): @@ -637,6 +649,7 @@ def prescriber_check_pe_email(request, template_name="signup/prescriber_check_pe return render(request, template_name, context) +@login_not_required @valid_prescriber_signup_session_required @push_url_in_history(global_constants.ITOU_SESSION_PRESCRIBER_SIGNUP_KEY) def prescriber_pole_emploi_user(request, template_name="signup/prescriber_pole_emploi_user.html"): @@ -676,6 +689,7 @@ def prescriber_pole_emploi_user(request, template_name="signup/prescriber_pole_e return render(request, template_name, context) +@login_not_required @valid_prescriber_signup_session_required @push_url_in_history(global_constants.ITOU_SESSION_PRESCRIBER_SIGNUP_KEY) def prescriber_user(request, template_name="signup/prescriber_user.html"): @@ -846,6 +860,7 @@ def _get_session_siae(self): ) +@login_not_required def facilitator_search(request, template_name="signup/facilitator_search.html"): form = forms.FacilitatorSearchForm(data=request.POST or None) if request.method == "POST" and form.is_valid(): @@ -859,7 +874,7 @@ def facilitator_search(request, template_name="signup/facilitator_search.html"): return render(request, template_name, context) -class FacilitatorUserView(FacilitatorBaseMixin, TemplateView): +class FacilitatorUserView(LoginNotRequiredMixin, FacilitatorBaseMixin, TemplateView): """ Display Inclusion Connect button. This page is also shown if an error is detected during @@ -890,7 +905,7 @@ def get_context_data(self, **kwargs): } -class FacilitatorJoinView(FacilitatorBaseMixin, View): +class FacilitatorJoinView(LoginNotRequiredMixin, FacilitatorBaseMixin, View): def get(self, request, *args, **kwargs): self.company_to_create.auth_email = request.user.email self.company_to_create.created_by = request.user diff --git a/itou/www/stats/views.py b/itou/www/stats/views.py index 9aeb95ce51..0b6d5406a0 100644 --- a/itou/www/stats/views.py +++ b/itou/www/stats/views.py @@ -15,7 +15,7 @@ """ from django.conf import settings -from django.contrib.auth.decorators import login_required +from django.contrib.auth.decorators import login_not_required, login_required from django.core.exceptions import PermissionDenied from django.http import HttpResponseNotFound, HttpResponseRedirect from django.shortcuts import render @@ -175,6 +175,7 @@ def render_stats(request, context, params=None, template_name="stats/stats.html" return render(request, template_name, base_context) +@login_not_required def stats_public(request): """ Public basic stats (signed and embedded version) diff --git a/tests/www/apply/test_submit.py b/tests/www/apply/test_submit.py index 7b2613c7e6..98aed0271f 100644 --- a/tests/www/apply/test_submit.py +++ b/tests/www/apply/test_submit.py @@ -3793,15 +3793,15 @@ def test_anonymous_step_1(self, client): def test_anonymous_step_2(self, client): response = client.get(self.step_2_url) - assert response.status_code == 403 + assertRedirects(response, reverse("account_login") + f"?next={self.step_2_url}") def test_anonymous_step_3(self, client): response = client.get(self.step_3_url) - assert response.status_code == 403 + assertRedirects(response, reverse("account_login") + f"?next={self.step_3_url}") def test_anonymous_step_end(self, client): response = client.get(self.step_end_url) - assert response.status_code == 403 + assertRedirects(response, reverse("account_login") + f"?next={self.step_end_url}") def test_as_job_seeker(self, client): self._check_nothing_permitted(client, self.job_seeker) @@ -3948,15 +3948,15 @@ def test_anonymous_step_1(self, client): def test_anonymous_step_2(self, client): response = client.get(self.step_2_url) - assert response.status_code == 403 + assertRedirects(response, reverse("account_login") + f"?next={self.step_2_url}") def test_anonymous_step_3(self, client): response = client.get(self.step_3_url) - assert response.status_code == 403 + assertRedirects(response, reverse("account_login") + f"?next={self.step_3_url}") def test_anonymous_step_end(self, client): response = client.get(self.step_end_url) - assert response.status_code == 403 + assertRedirects(response, reverse("account_login") + f"?next={self.step_end_url}") def test_as_job_seeker(self, client): self._check_nothing_permitted(client, self.job_seeker) diff --git a/tests/www/signup/test_prescriber.py b/tests/www/signup/test_prescriber.py index 2024295c17..2a79e13891 100644 --- a/tests/www/signup/test_prescriber.py +++ b/tests/www/signup/test_prescriber.py @@ -1213,9 +1213,14 @@ def test_permission_denied_when_skiping_first_step(self, client, subtests): reverse("signup:prescriber_check_pe_email"), reverse("signup:prescriber_pole_emploi_user"), reverse("signup:prescriber_user"), - reverse("signup:prescriber_join_org"), ] for url in urls: with subtests.test(url=url): response = client.get(url) assert response.status_code == 403 + # This view requires to be logged in + url = reverse("signup:prescriber_join_org") + with subtests.test(url=url): + client.force_login(PrescriberFactory()) + response = client.get(url) + assert response.status_code == 403 From 4c00d1f3f6f6585c627982f72fa89159e055f81f Mon Sep 17 00:00:00 2001 From: Xavier Fernandez Date: Tue, 10 Dec 2024 13:57:52 +0100 Subject: [PATCH 2/4] remove most LoginRequiredMixin uses & simplify setup() code Since LoginRequiredMiddleware now ensures that the user is authenticated --- itou/www/apply/views/process_views.py | 51 ++++++-------- itou/www/apply/views/submit_views.py | 89 +++++++++--------------- itou/www/approvals_views/views.py | 47 ++++++------- itou/www/dashboard/views.py | 5 +- itou/www/employee_record_views/views.py | 7 +- itou/www/employees_views/views.py | 10 ++- itou/www/job_seekers_views/views.py | 25 +++---- itou/www/logout/views.py | 3 +- itou/www/siae_evaluations_views/views.py | 6 +- itou/www/signup/views.py | 3 +- 10 files changed, 91 insertions(+), 155 deletions(-) diff --git a/itou/www/apply/views/process_views.py b/itou/www/apply/views/process_views.py index f91e9bb44c..9418de9b98 100644 --- a/itou/www/apply/views/process_views.py +++ b/itou/www/apply/views/process_views.py @@ -398,7 +398,7 @@ class RefuseViewStep(enum.StrEnum): do_not_call_in_templates = enum.nonmember(True) -class JobApplicationRefuseView(LoginRequiredMixin, NamedUrlSessionWizardView): +class JobApplicationRefuseView(NamedUrlSessionWizardView): template_name = "apply/process_refuse.html" form_list = [ (RefuseViewStep.REASON, JobApplicationRefusalReasonForm), @@ -412,11 +412,10 @@ class JobApplicationRefuseView(LoginRequiredMixin, NamedUrlSessionWizardView): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - if request.user.is_authenticated: - self.job_application = get_object_or_404( - JobApplication.objects.is_active_company_member(request.user).select_related("job_seeker"), - pk=kwargs["job_application_id"], - ) + self.job_application = get_object_or_404( + JobApplication.objects.is_active_company_member(request.user).select_related("job_seeker"), + pk=kwargs["job_application_id"], + ) def check_wizard_state(self, *args, **kwargs): # Redirect to job application details if the state is not refusable @@ -754,20 +753,19 @@ class ApplicationOverrideMixin: additionnal_related_models = [] def setup(self, request, *args, **kwargs): - if request.user.is_authenticated: - self.job_application = get_object_or_404( - JobApplication.objects.is_active_company_member(request.user).select_related( - "job_seeker", "to_company", *self.additionnal_related_models - ), - pk=kwargs["job_application_id"], - ) - kwargs["job_seeker_public_id"] = self.job_application.job_seeker.public_id + self.job_application = get_object_or_404( + JobApplication.objects.is_active_company_member(request.user).select_related( + "job_seeker", "to_company", *self.additionnal_related_models + ), + pk=kwargs["job_application_id"], + ) + kwargs["job_seeker_public_id"] = self.job_application.job_seeker.public_id return super().setup(request, *args, **kwargs) class JobApplicationExternalTransferStep2View(ApplicationOverrideMixin, ApplicationJobsView): def dispatch(self, request, *args, **kwargs): - if request.user.is_authenticated and self.company in request.organizations: + if self.company in request.organizations: # This is not an external transfer url = reverse( "apply:job_application_internal_transfer", @@ -812,7 +810,7 @@ class JobApplicationExternalTransferStep3View(ApplicationOverrideMixin, Applicat form_class = TransferJobApplicationForm def dispatch(self, request, *args, **kwargs): - if request.user.is_authenticated and not self.apply_session.exists(): + if not self.apply_session.exists(): return HttpResponseRedirect( reverse( "apply:job_application_external_transfer_step_2", @@ -868,11 +866,7 @@ def get_back_url(self): class JobApplicationExternalTransferStepEndView(ApplicationEndView): def setup(self, request, *args, **kwargs): - job_app_qs = JobApplication.objects.all() - if request.user.is_authenticated: - # Only check the user's ownership if he's authenticated - # because if he's not he will be redirected to login so we don't care - job_app_qs = JobApplication.objects.prescriptions_of(request.user, request.current_organization) + job_app_qs = JobApplication.objects.prescriptions_of(request.user, request.current_organization) job_application = get_object_or_404(job_app_qs, pk=kwargs["job_application_id"]) @@ -890,20 +884,17 @@ def get_context_data(self, **kwargs): } -class JobApplicationInternalTranferView(LoginRequiredMixin, TemplateView): +class JobApplicationInternalTranferView(TemplateView): template_name = "apply/process_internal_transfer.html" def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - if request.user.is_authenticated: - self.job_application = get_object_or_404( - JobApplication.objects.is_active_company_member(request.user).select_related( - "job_seeker", "to_company" - ), - pk=kwargs["job_application_id"], - ) - self.company = get_object_or_404(Company.objects.with_has_active_members(), pk=kwargs["company_pk"]) + self.job_application = get_object_or_404( + JobApplication.objects.is_active_company_member(request.user).select_related("job_seeker", "to_company"), + pk=kwargs["job_application_id"], + ) + self.company = get_object_or_404(Company.objects.with_has_active_members(), pk=kwargs["company_pk"]) def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) | { diff --git a/itou/www/apply/views/submit_views.py b/itou/www/apply/views/submit_views.py index d306105df6..133ae3a5f5 100644 --- a/itou/www/apply/views/submit_views.py +++ b/itou/www/apply/views/submit_views.py @@ -3,7 +3,6 @@ from dateutil.relativedelta import relativedelta from django.contrib.auth.decorators import login_required -from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from django.core.files.storage import storages from django.forms import ValidationError @@ -81,7 +80,7 @@ def _get_job_seeker_to_apply_for(request): return job_seeker -class ApplyStepBaseView(LoginRequiredMixin, TemplateView): +class ApplyStepBaseView(TemplateView): def __init__(self): super().__init__() self.company = None @@ -100,36 +99,27 @@ def setup(self, request, *args, **kwargs): ) self.apply_session = SessionNamespace(request.session, f"job_application-{self.company.pk}") self.hire_process = kwargs.pop("hire_process", False) - self.prescription_process = ( - not self.hire_process - and request.user.is_authenticated - and ( - request.user.is_prescriber - or (request.user.is_employer and self.company != request.current_organization) - ) + self.prescription_process = not self.hire_process and ( + request.user.is_prescriber or (request.user.is_employer and self.company != request.current_organization) ) self.auto_prescription_process = ( - not self.hire_process - and request.user.is_authenticated - and request.user.is_employer - and self.company == request.current_organization + not self.hire_process and request.user.is_employer and self.company == request.current_organization ) super().setup(request, *args, **kwargs) def dispatch(self, request, *args, **kwargs): if not self.is_gps: - if request.user.is_authenticated: - if self.hire_process and request.user.kind != UserKind.EMPLOYER: - raise PermissionDenied("Seuls les employeurs sont autorisés à déclarer des embauches") - elif self.hire_process and not self.company.has_member(request.user): - raise PermissionDenied("Vous ne pouvez déclarer une embauche que dans votre structure.") - elif request.user.kind not in [ - UserKind.JOB_SEEKER, - UserKind.PRESCRIBER, - UserKind.EMPLOYER, - ]: - raise PermissionDenied("Vous n'êtes pas autorisé à déposer de candidature.") + if self.hire_process and request.user.kind != UserKind.EMPLOYER: + raise PermissionDenied("Seuls les employeurs sont autorisés à déclarer des embauches") + elif self.hire_process and not self.company.has_member(request.user): + raise PermissionDenied("Vous ne pouvez déclarer une embauche que dans votre structure.") + elif request.user.kind not in [ + UserKind.JOB_SEEKER, + UserKind.PRESCRIBER, + UserKind.EMPLOYER, + ]: + raise PermissionDenied("Vous n'êtes pas autorisé à déposer de candidature.") if not self.company.has_active_members: raise PermissionDenied( @@ -191,9 +181,6 @@ def __init__(self): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - if not request.user.is_authenticated: - # Do nothing, LoginRequiredMixin will raise in dispatch() - return self.job_seeker = get_object_or_404( User.objects.filter(kind=UserKind.JOB_SEEKER), public_id=kwargs["job_seeker_public_id"] @@ -352,10 +339,7 @@ def __init__(self): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - - if request.user.is_authenticated: - # Otherwise LoginRequiredMixin will raise in dispatch() - self.previous_applications = self.get_previous_applications_queryset() + self.previous_applications = self.get_previous_applications_queryset() def get_next_url(self): if self.hire_process: @@ -452,7 +436,7 @@ def get_context_data(self, **kwargs): class RequireApplySessionMixin: def dispatch(self, request, *args, **kwargs): - if request.user.is_authenticated and not self.apply_session.exists(): + if not self.apply_session.exists(): return HttpResponseRedirect( reverse( "apply:application_jobs", @@ -495,22 +479,20 @@ def get_next_url(self): ) def dispatch(self, request, *args, **kwargs): - if request.user.is_authenticated: - # Otherwise LoginRequiredMixin will raise in dispatch() - bypass_eligibility_conditions = [ - # Don't perform an eligibility diagnosis is the SIAE doesn't need it, - not self.company.is_subject_to_eligibility_rules, - # Only "authorized prescribers" can perform an eligibility diagnosis. - not ( - request.user.is_prescriber - and request.current_organization - and request.current_organization.is_authorized - ), - # No need for eligibility diagnosis if the job seeker already have a PASS IAE - self.job_seeker.has_valid_approval, - ] - if any(bypass_eligibility_conditions): - return HttpResponseRedirect(self.get_next_url()) + bypass_eligibility_conditions = [ + # Don't perform an eligibility diagnosis is the SIAE doesn't need it, + not self.company.is_subject_to_eligibility_rules, + # Only "authorized prescribers" can perform an eligibility diagnosis. + not ( + request.user.is_prescriber + and request.current_organization + and request.current_organization.is_authorized + ), + # No need for eligibility diagnosis if the job seeker already have a PASS IAE + self.job_seeker.has_valid_approval, + ] + if any(bypass_eligibility_conditions): + return HttpResponseRedirect(self.get_next_url()) return super().dispatch(request, *args, **kwargs) @@ -559,10 +541,6 @@ def __init__(self): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - if not request.user.is_authenticated: - # Do nothing, LoginRequiredMixin will raise in dispatch() - return - if self.company.kind != CompanyKind.GEIQ: raise Http404("This form is only for GEIQ") @@ -588,7 +566,7 @@ def get_next_url(self): def dispatch(self, request, *args, **kwargs): # GEIQ eligibility form during job application process is only available to authorized prescribers - if request.user.is_authenticated and not request.user.is_prescriber_with_authorized_org: + if not request.user.is_prescriber_with_authorized_org: return HttpResponseRedirect(self.get_next_url()) return super().dispatch(request, *args, **kwargs) @@ -651,11 +629,6 @@ def get_form_kwargs(self): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - - if not request.user.is_authenticated: - # Do nothing, LoginRequiredMixin will raise in dispatch() - return - self.form = self.form_class(**self.get_form_kwargs()) def get_next_url(self, job_application): diff --git a/itou/www/approvals_views/views.py b/itou/www/approvals_views/views.py index 88907184d2..3c0eea7582 100644 --- a/itou/www/approvals_views/views.py +++ b/itou/www/approvals_views/views.py @@ -5,7 +5,7 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin +from django.contrib.auth.mixins import UserPassesTestMixin from django.core.exceptions import PermissionDenied from django.core.files.storage import default_storage from django.db import IntegrityError @@ -53,7 +53,7 @@ logger = logging.getLogger(__name__) -class ApprovalBaseViewMixin(LoginRequiredMixin): +class ApprovalBaseViewMixin: model = Approval def __init__(self): @@ -62,11 +62,10 @@ def __init__(self): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - if request.user.is_authenticated: - self.siae = get_current_company_or_404(request) + self.siae = get_current_company_or_404(request) - if not self.siae.is_subject_to_eligibility_rules: - raise PermissionDenied + if not self.siae.is_subject_to_eligibility_rules: + raise PermissionDenied def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -126,7 +125,7 @@ def get_context_data(self, **kwargs): return context -class ApprovalDetailView(LoginRequiredMixin, UserPassesTestMixin, DetailView): +class ApprovalDetailView(UserPassesTestMixin, DetailView): model = Approval queryset = Approval.objects.select_related("user__jobseeker_profile").prefetch_related( # Useful for get_suspensions method and the approval remainder field @@ -138,10 +137,8 @@ class ApprovalDetailView(LoginRequiredMixin, UserPassesTestMixin, DetailView): template_name = "approvals/details.html" def test_func(self): - return self.request.user.is_authenticated and ( - # More checks are performed in get_context_data method - self.request.user.is_prescriber or self.request.user.is_employer or self.request.user.is_job_seeker - ) + # More checks are performed in get_context_data method + return self.request.user.is_prescriber or self.request.user.is_employer or self.request.user.is_job_seeker def get_prolongation_and_requests(self, approval): def _format_for_template(user, org): @@ -406,11 +403,10 @@ def _clear_errors(self): def setup(self, request, approval_id, *args, **kwargs): super().setup(request, *args, **kwargs) - if request.user.is_authenticated: - self.siae = get_current_company_or_404(request) - if not self.siae.is_subject_to_eligibility_rules: - raise PermissionDenied() - self.approval = get_object_or_404(Approval, pk=approval_id) + self.siae = get_current_company_or_404(request) + if not self.siae.is_subject_to_eligibility_rules: + raise PermissionDenied() + self.approval = get_object_or_404(Approval, pk=approval_id) if not self.approval.can_be_prolonged: raise PermissionDenied() @@ -507,20 +503,17 @@ def prolongation_request_report_file(request, prolongation_request_id): return HttpResponseRedirect(default_storage.url(prolongation_request.report_file_id)) -class ProlongationRequestViewMixin(LoginRequiredMixin): +class ProlongationRequestViewMixin: def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - if request.user.is_authenticated: - self.prolongation_request = get_object_or_404( - ProlongationRequest.objects.filter( - prescriber_organization=get_current_org_or_404(request) - ).select_related( - "approval__user", - "deny_information", - ), - pk=kwargs["prolongation_request_id"], - ) + self.prolongation_request = get_object_or_404( + ProlongationRequest.objects.filter(prescriber_organization=get_current_org_or_404(request)).select_related( + "approval__user", + "deny_information", + ), + pk=kwargs["prolongation_request_id"], + ) def get_context_data(self, **kwargs): return super().get_context_data(**kwargs) | { diff --git a/itou/www/dashboard/views.py b/itou/www/dashboard/views.py index 57cf30cf76..63efb068af 100644 --- a/itou/www/dashboard/views.py +++ b/itou/www/dashboard/views.py @@ -5,7 +5,6 @@ from django.contrib import auth, messages from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth.decorators import login_required -from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from django.db.models import F from django.http import Http404, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect @@ -390,11 +389,11 @@ def api_token(request, template_name="dashboard/api_token.html"): return render(request, template_name, context) -class AccountMigrationView(LoginRequiredMixin, TemplateView): +class AccountMigrationView(TemplateView): template_name = "account/activate_inclusion_connect_account.html" def dispatch(self, request, *args, **kwargs): - if request.user.is_authenticated and request.user.kind not in MATOMO_ACCOUNT_TYPE: + if request.user.kind not in MATOMO_ACCOUNT_TYPE: return HttpResponseRedirect(reverse("dashboard:index")) return super().dispatch(request, *args, **kwargs) diff --git a/itou/www/employee_record_views/views.py b/itou/www/employee_record_views/views.py index 568e0123cd..c51e42ec54 100644 --- a/itou/www/employee_record_views/views.py +++ b/itou/www/employee_record_views/views.py @@ -1,6 +1,5 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied, ValidationError from django.db.models import Count from django.http.response import HttpResponseRedirect @@ -66,7 +65,7 @@ def _show_add_choose_approval_form(wizard): return bool(cleaned_data.get("employee")) -class AddView(LoginRequiredMixin, NamedUrlSessionWizardView): +class AddView(NamedUrlSessionWizardView): template_name = "employee_record/add.html" form_list = [ ("choose-employee", AddEmployeeRecordChooseEmployeeForm), @@ -77,10 +76,6 @@ class AddView(LoginRequiredMixin, NamedUrlSessionWizardView): } def dispatch(self, request, *args, **kwargs): - # Do LoginRequiredMixin.dispatch() here so we get the 404 and the redirect before the PermissionDenied - if not request.user.is_authenticated: - return self.handle_no_permission() - self.company = get_current_company_or_404(request) if not self.company.can_use_employee_record: raise PermissionDenied diff --git a/itou/www/employees_views/views.py b/itou/www/employees_views/views.py index 7804f35081..dc43065c71 100644 --- a/itou/www/employees_views/views.py +++ b/itou/www/employees_views/views.py @@ -1,7 +1,6 @@ import contextlib import logging -from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from django.db.models import Exists, OuterRef, Prefetch from django.urls import reverse_lazy @@ -23,7 +22,7 @@ logger = logging.getLogger(__name__) -class EmployeeDetailView(LoginRequiredMixin, DetailView): +class EmployeeDetailView(DetailView): model = User queryset = User.objects.filter(kind=UserKind.JOB_SEEKER).select_related("jobseeker_profile") template_name = "employees/detail.html" @@ -33,11 +32,10 @@ class EmployeeDetailView(LoginRequiredMixin, DetailView): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - if request.user.is_authenticated: - self.siae = get_current_company_or_404(request) + self.siae = get_current_company_or_404(request) - if not self.siae.is_subject_to_eligibility_rules: - raise PermissionDenied + if not self.siae.is_subject_to_eligibility_rules: + raise PermissionDenied def get_queryset(self): return ( diff --git a/itou/www/job_seekers_views/views.py b/itou/www/job_seekers_views/views.py index a5292da966..e7a04b2e40 100644 --- a/itou/www/job_seekers_views/views.py +++ b/itou/www/job_seekers_views/views.py @@ -1,7 +1,7 @@ import logging from django.contrib import messages -from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin +from django.contrib.auth.mixins import UserPassesTestMixin from django.core.exceptions import PermissionDenied from django.db import transaction from django.db.models import Count, DateTimeField, Exists, IntegerField, Max, OuterRef, Subquery @@ -44,7 +44,7 @@ logger = logging.getLogger(__name__) -class JobSeekerDetailView(LoginRequiredMixin, UserPassesTestMixin, DetailView): +class JobSeekerDetailView(UserPassesTestMixin, DetailView): model = User queryset = User.objects.select_related("jobseeker_profile") template_name = "job_seekers_views/details.html" @@ -53,9 +53,7 @@ class JobSeekerDetailView(LoginRequiredMixin, UserPassesTestMixin, DetailView): context_object_name = "job_seeker" def test_func(self): - return self.request.user.is_authenticated and ( - self.request.user.is_prescriber or self.request.user.is_employer - ) + return self.request.user.is_prescriber or self.request.user.is_employer def get_context_data(self, **kwargs): geiq_eligibility_diagnosis = None @@ -112,7 +110,7 @@ def get_context_data(self, **kwargs): } -class JobSeekerListView(LoginRequiredMixin, UserPassesTestMixin, ListView): +class JobSeekerListView(UserPassesTestMixin, ListView): model = User queryset = ( User.objects.filter(kind=UserKind.JOB_SEEKER).order_by("first_name", "last_name").prefetch_related("approvals") @@ -133,7 +131,7 @@ def setup(self, request, *args, **kwargs): ) def test_func(self): - return self.request.user.is_authenticated and self.request.user.is_prescriber + return self.request.user.is_prescriber def get_template_names(self): return ["job_seekers_views/includes/list_results.html" if self.request.htmx else "job_seekers_views/list.html"] @@ -186,7 +184,7 @@ def get_queryset(self): return query -class JobSeekerBaseView(LoginRequiredMixin, TemplateView): +class JobSeekerBaseView(TemplateView): def __init__(self): super().__init__() self.company = None @@ -211,7 +209,6 @@ def setup(self, request, *args, session_uuid, hire_process=False, **kwargs): self.prescription_process = ( not self.hire_process and not self.is_gps - and request.user.is_authenticated and ( request.user.is_prescriber or (request.user.is_employer and self.company != request.current_organization) @@ -220,7 +217,6 @@ def setup(self, request, *args, session_uuid, hire_process=False, **kwargs): self.auto_prescription_process = ( not self.hire_process and not self.is_gps - and request.user.is_authenticated and request.user.is_employer and self.company == request.current_organization ) @@ -285,7 +281,7 @@ def setup(self, request, *args, **kwargs): self.form = CheckJobSeekerNirForm(job_seeker=self.job_seeker, data=request.POST or None) def dispatch(self, request, *args, **kwargs): - if request.user.is_authenticated and not self.job_seeker.is_job_seeker: + if not self.job_seeker.is_job_seeker: logger.info(f"dispatch ({request.path}) : {request.user.kind} in jobseeker tunnel") return HttpResponseRedirect(reverse("apply:start", kwargs={"company_pk": self.company.pk})) return super().dispatch(request, *args, **kwargs) @@ -764,9 +760,7 @@ def get_job_seeker_queryset(self): def setup(self, request, *args, **kwargs): self.job_seeker = get_object_or_404(self.get_job_seeker_queryset(), public_id=kwargs["job_seeker_public_id"]) self.job_seeker_session = SessionNamespace(request.session, f"job_seeker-{self.job_seeker.public_id}") - if request.user.is_authenticated and ( - request.user.is_job_seeker or not request.user.can_view_personal_information(self.job_seeker) - ): + if request.user.is_job_seeker or not request.user.can_view_personal_information(self.job_seeker): # Since the link leading to this process isn't visible to those users, this should never happen raise PermissionDenied("Votre utilisateur n'est pas autorisé à vérifier les informations de ce candidat") super().setup(request, *args, **kwargs) @@ -824,9 +818,6 @@ def get_job_seeker_queryset(self): def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - if not request.user.is_authenticated: - # Do nothing, LoginRequiredMixin will raise in dispatch() - return if not self.job_seeker_session.exists(): self.job_seeker_session.init({"user": {}}) session_nir = self.job_seeker_session.get("profile", {}).get("nir") diff --git a/itou/www/logout/views.py b/itou/www/logout/views.py index 0fed061ff2..2b38e9ed88 100644 --- a/itou/www/logout/views.py +++ b/itou/www/logout/views.py @@ -1,11 +1,10 @@ -from django.contrib.auth.mixins import LoginRequiredMixin from django.shortcuts import redirect from django.views.generic import TemplateView from itou.www.logout.enums import LogoutWarning -class LogoutWarningView(LoginRequiredMixin, TemplateView): +class LogoutWarningView(TemplateView): """ Logout view used when the perms middleware detects an issue """ diff --git a/itou/www/siae_evaluations_views/views.py b/itou/www/siae_evaluations_views/views.py index 81b3047dec..18079d351c 100644 --- a/itou/www/siae_evaluations_views/views.py +++ b/itou/www/siae_evaluations_views/views.py @@ -1,6 +1,5 @@ from django.contrib import messages from django.contrib.auth.decorators import login_not_required, login_required -from django.contrib.auth.mixins import LoginRequiredMixin from django.core.files.storage import default_storage from django.db.models import Q from django.http import Http404, HttpResponseForbidden, HttpResponseRedirect @@ -209,15 +208,14 @@ def evaluation_campaign_data_context(evaluated_siae): return context -class InstitutionEvaluatedSiaeNotifyMixin(LoginRequiredMixin, SingleObjectMixin): +class InstitutionEvaluatedSiaeNotifyMixin(SingleObjectMixin): model = EvaluatedSiae context_object_name = "evaluated_siae" pk_url_kwarg = "evaluated_siae_pk" def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) - if request.user.is_authenticated: - self.institution = get_current_institution_or_404(self.request) + self.institution = get_current_institution_or_404(self.request) def get_queryset(self): return ( diff --git a/itou/www/signup/views.py b/itou/www/signup/views.py index 036803190a..7eb7ab37d4 100644 --- a/itou/www/signup/views.py +++ b/itou/www/signup/views.py @@ -10,7 +10,6 @@ from django.contrib import auth, messages from django.contrib.auth import REDIRECT_FIELD_NAME, login from django.contrib.auth.decorators import login_not_required, login_required -from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from django.db import Error, transaction from django.http import HttpResponseRedirect @@ -318,7 +317,7 @@ def get_context_data(self, **kwargs): } -class CompanyJoinView(LoginRequiredMixin, CompanyBaseView): +class CompanyJoinView(CompanyBaseView): def get(self, request, *args, **kwargs): if not request.user.is_employer: logger.error("A non staff user tried to join a company") From 501e8ed57c655fd21331866406576a3b3f429873 Mon Sep 17 00:00:00 2001 From: Xavier Fernandez Date: Wed, 11 Dec 2024 11:43:37 +0100 Subject: [PATCH 3/4] Remove now useless @login_required decorators --- itou/www/apply/views/edit_views.py | 3 -- itou/www/apply/views/list_views.py | 8 ---- itou/www/apply/views/process_views.py | 15 ------ itou/www/apply/views/submit_views.py | 5 -- itou/www/approvals_views/views.py | 10 ---- itou/www/autocomplete/views.py | 3 +- itou/www/companies_views/views.py | 17 +------ itou/www/dashboard/views.py | 11 +---- itou/www/employee_record_views/views.py | 10 ---- itou/www/geiq_views/views.py | 8 ---- itou/www/gps/views.py | 5 -- itou/www/institutions_views/views.py | 4 -- itou/www/invitations_views/views.py | 8 +--- itou/www/itou_staff_views/views.py | 6 --- itou/www/prescribers_views/views.py | 7 +-- itou/www/siae_evaluations_views/views.py | 15 +----- itou/www/signup/views.py | 3 +- itou/www/stats/views.py | 61 +----------------------- itou/www/welcoming_tour/views.py | 2 - 19 files changed, 8 insertions(+), 193 deletions(-) diff --git a/itou/www/apply/views/edit_views.py b/itou/www/apply/views/edit_views.py index 833b00169c..b1761c7492 100644 --- a/itou/www/apply/views/edit_views.py +++ b/itou/www/apply/views/edit_views.py @@ -1,5 +1,4 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.http import Http404, HttpResponseRedirect from django.shortcuts import get_object_or_404, render @@ -13,7 +12,6 @@ from itou.www.apply.forms import EditHiringDateForm -@login_required @check_user(lambda user: user.is_employer) def edit_contract_start_date(request, job_application_id, template_name="apply/edit_contract_start_date.html"): """ @@ -53,7 +51,6 @@ def edit_contract_start_date(request, job_application_id, template_name="apply/e return render(request, template_name, context) -@login_required @require_POST @check_user(lambda user: user.is_employer) def archive_view(request, job_application_id, *, action): diff --git a/itou/www/apply/views/list_views.py b/itou/www/apply/views/list_views.py index 7390548702..393dc93340 100644 --- a/itou/www/apply/views/list_views.py +++ b/itou/www/apply/views/list_views.py @@ -2,7 +2,6 @@ from collections import defaultdict from django.conf import settings -from django.contrib.auth.decorators import login_required from django.db import models from django.db.models import Count, Exists, F, OuterRef, Q, Subquery from django.shortcuts import render @@ -102,7 +101,6 @@ def _add_administrative_criteria(job_applications): job_application.preloaded_administrative_criteria_extra_nb = extra_nb -@login_required @check_user(lambda u: u.is_job_seeker) def list_for_job_seeker(request, template_name="apply/list_for_job_seeker.html"): """ @@ -179,7 +177,6 @@ def annotate_title(base_title, archived_choice): raise ValueError(archived_choice) -@login_required @check_user(lambda u: u.is_prescriber or u.is_employer) def list_prescriptions(request, template_name="apply/list_prescriptions.html"): """ @@ -227,7 +224,6 @@ def list_prescriptions(request, template_name="apply/list_prescriptions.html"): ) -@login_required @check_user(lambda u: u.is_prescriber or u.is_employer) def list_prescriptions_exports(request, template_name="apply/list_of_available_exports.html"): """ @@ -248,7 +244,6 @@ def list_prescriptions_exports(request, template_name="apply/list_of_available_e return render(request, template_name, context) -@login_required @check_user(lambda u: u.is_prescriber or u.is_employer) def list_prescriptions_exports_download(request, month_identifier=None): """ @@ -267,7 +262,6 @@ def list_prescriptions_exports_download(request, month_identifier=None): return stream_xlsx_export(job_applications, filename, request_user=request.user) -@login_required def list_for_siae(request, template_name="apply/list_for_siae.html"): """ List of applications for an SIAE. @@ -356,7 +350,6 @@ def list_for_siae(request, template_name="apply/list_for_siae.html"): ) -@login_required def list_for_siae_exports(request, template_name="apply/list_of_available_exports.html"): """ List of applications for a SIAE, sorted by month, displaying the count of applications per month @@ -378,7 +371,6 @@ def list_for_siae_exports(request, template_name="apply/list_of_available_export return render(request, template_name, context) -@login_required def list_for_siae_exports_download(request, month_identifier=None): """ List of applications for a SIAE for a given month identifier (YYYY-mm), diff --git a/itou/www/apply/views/process_views.py b/itou/www/apply/views/process_views.py index 9418de9b98..a9c20f3e70 100644 --- a/itou/www/apply/views/process_views.py +++ b/itou/www/apply/views/process_views.py @@ -7,7 +7,6 @@ import sentry_sdk from django.conf import settings from django.contrib import messages -from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from django.db import transaction @@ -91,7 +90,6 @@ def job_application_sender_left_org(job_app): return False -@login_required def details_for_jobseeker(request, job_application_id, template_name="apply/process_details.html"): """ Detail of an application for a JOBSEEKER @@ -170,7 +168,6 @@ def details_for_jobseeker(request, job_application_id, template_name="apply/proc return render(request, template_name, context) -@login_required @check_user(lambda user: user.is_employer) def details_for_company(request, job_application_id, template_name="apply/process_details_company.html"): """ @@ -282,7 +279,6 @@ def details_for_company(request, job_application_id, template_name="apply/proces return render(request, template_name, context) -@login_required @check_user(lambda u: u.is_prescriber or u.is_employer) def details_for_prescriber(request, job_application_id, template_name="apply/process_details.html"): """ @@ -365,7 +361,6 @@ def details_for_prescriber(request, job_application_id, template_name="apply/pro return render(request, template_name, context) -@login_required @require_POST @check_user(lambda user: user.is_employer) def process(request, job_application_id): @@ -517,7 +512,6 @@ def get_step_url(self, step): return reverse(f"apply:{self.url_name}", kwargs={"job_application_id": self.job_application.pk, "step": step}) -@login_required @check_user(lambda user: user.is_employer) def postpone(request, job_application_id, template_name="apply/process_postpone.html"): queryset = JobApplication.objects.is_active_company_member(request.user) @@ -551,7 +545,6 @@ def postpone(request, job_application_id, template_name="apply/process_postpone. return render(request, template_name, context) -@login_required @check_user(lambda user: user.is_employer) def accept(request, job_application_id, template_name="apply/process_accept.html"): """ @@ -620,7 +613,6 @@ class ReloadJobDescriptionFields(AcceptHTMXFragmentView): NO_ERROR_FIELDS = ("appellation", "location") -@login_required @require_POST @check_user(lambda user: user.is_employer) def cancel(request, job_application_id): @@ -645,7 +637,6 @@ def cancel(request, job_application_id): return HttpResponseRedirect(next_url) -@login_required @check_user(lambda user: user.is_employer) def transfer(request, job_application_id): queryset = JobApplication.objects.is_active_company_member(request.user) @@ -906,7 +897,6 @@ def get_context_data(self, **kwargs): } -@login_required @require_POST @check_user(lambda user: user.is_employer) def send_diagoriente_invite(request, job_application_id): @@ -928,7 +918,6 @@ def send_diagoriente_invite(request, job_application_id): return HttpResponseRedirect(redirect_url) -@login_required @check_user(lambda user: user.is_employer) def eligibility(request, job_application_id, template_name="apply/process_eligibility.html"): """ @@ -952,7 +941,6 @@ def eligibility(request, job_application_id, template_name="apply/process_eligib ) -@login_required @check_user(lambda user: user.is_employer) def geiq_eligibility(request, job_application_id, template_name="apply/process_geiq_eligibility.html"): queryset = JobApplication.objects.is_active_company_member(request.user) @@ -976,7 +964,6 @@ def geiq_eligibility(request, job_application_id, template_name="apply/process_g ) -@login_required @check_user(lambda user: user.is_employer) def geiq_eligibility_criteria( request, @@ -1031,7 +1018,6 @@ def delete_prior_action(request, job_application_id, prior_action_id): return HttpResponse(content) -@login_required @check_user(lambda user: user.is_employer) def add_or_modify_prior_action(request, job_application_id, prior_action_id=None): queryset = JobApplication.objects.is_active_company_member(request.user) @@ -1132,7 +1118,6 @@ def add_or_modify_prior_action(request, job_application_id, prior_action_id=None return render(request, "apply/includes/job_application_prior_action_form.html", context) -@login_required @require_POST @check_user(lambda user: user.is_employer) def rdv_insertion_invite(request, job_application_id, for_detail=False): diff --git a/itou/www/apply/views/submit_views.py b/itou/www/apply/views/submit_views.py index 133ae3a5f5..393f6e8ba6 100644 --- a/itou/www/apply/views/submit_views.py +++ b/itou/www/apply/views/submit_views.py @@ -2,7 +2,6 @@ import uuid from dateutil.relativedelta import relativedelta -from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.core.files.storage import storages from django.forms import ValidationError @@ -781,7 +780,6 @@ def get_context_data(self, **kwargs): } -@login_required def eligibility_for_hire( request, company_pk, @@ -818,7 +816,6 @@ def eligibility_for_hire( ) -@login_required def geiq_eligibility_for_hire( request, company_pk, @@ -855,7 +852,6 @@ def geiq_eligibility_for_hire( ) -@login_required def geiq_eligibility_criteria_for_hire(request, company_pk, job_seeker_public_id): company = get_object_or_404( Company.objects.filter(pk__in={org.pk for org in request.organizations}, kind=CompanyKind.GEIQ), pk=company_pk @@ -868,7 +864,6 @@ def geiq_eligibility_criteria_for_hire(request, company_pk, job_seeker_public_id ) -@login_required def hire_confirmation( request, company_pk, diff --git a/itou/www/approvals_views/views.py b/itou/www/approvals_views/views.py index 3c0eea7582..05b08209e0 100644 --- a/itou/www/approvals_views/views.py +++ b/itou/www/approvals_views/views.py @@ -4,7 +4,6 @@ from datetime import timedelta from django.contrib import messages -from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import UserPassesTestMixin from django.core.exceptions import PermissionDenied from django.core.files.storage import default_storage @@ -74,7 +73,6 @@ def get_context_data(self, **kwargs): # TODO(xfernandez): remove this redirect view in a few weeks -@login_required def approval_detail_redirect_to_employee_view(request, pk): siae = get_current_company_or_404(request) @@ -308,7 +306,6 @@ def prolongation_back_url(request): return get_safe_url(request, "back_url", fallback_url=reverse("dashboard:index")) -@login_required def declare_prolongation(request, approval_id, template_name="approvals/declare_prolongation.html"): """ Declare a prolongation for the given approval. @@ -468,7 +465,6 @@ class CheckContactDetailsView(DeclareProlongationHTMXFragmentView): clear_errors = ("contact_email", "contact_phone") -@login_required def prolongation_requests_list(request, template_name="approvals/prolongation_requests/list.html"): current_organization = get_current_org_or_404(request) if not current_organization.is_authorized: @@ -491,7 +487,6 @@ def prolongation_requests_list(request, template_name="approvals/prolongation_re @require_safe -@login_required def prolongation_request_report_file(request, prolongation_request_id): prolongation_request = get_object_or_404( ProlongationRequest, @@ -588,7 +583,6 @@ def get_step_url(self, step): return reverse(self.url_name, kwargs={"prolongation_request_id": self.prolongation_request.pk, "step": step}) -@login_required def suspend(request, approval_id, template_name="approvals/suspend.html"): siae = get_current_company_or_404(request) approval = get_object_or_404(Approval, pk=approval_id) @@ -623,7 +617,6 @@ def suspend(request, approval_id, template_name="approvals/suspend.html"): return render(request, template_name, context) -@login_required() def suspension_action_choice(request, suspension_id, template_name="approvals/suspension_action_choice.html"): siae = get_current_company_or_404(request) suspension = get_object_or_404( @@ -666,7 +659,6 @@ def suspension_action_choice(request, suspension_id, template_name="approvals/su return render(request, template_name, context) -@login_required def suspension_update(request, suspension_id, template_name="approvals/suspension_update.html"): """ Edit the given suspension. @@ -705,7 +697,6 @@ def suspension_update(request, suspension_id, template_name="approvals/suspensio return render(request, template_name, context) -@login_required() def suspension_update_enddate(request, suspension_id, template_name="approvals/suspension_update_enddate.html"): siae = get_current_company_or_404(request) suspension = get_object_or_404( @@ -748,7 +739,6 @@ def suspension_update_enddate(request, suspension_id, template_name="approvals/s return render(request, template_name, context) -@login_required def suspension_delete(request, suspension_id, template_name="approvals/suspension_delete.html"): """ Delete the given suspension. diff --git a/itou/www/autocomplete/views.py b/itou/www/autocomplete/views.py index a27081e9c7..2d3eaf0ea7 100644 --- a/itou/www/autocomplete/views.py +++ b/itou/www/autocomplete/views.py @@ -1,6 +1,6 @@ from datetime import datetime -from django.contrib.auth.decorators import login_not_required, login_required +from django.contrib.auth.decorators import login_not_required from django.db.models import F, Q, Value from django.db.models.functions import Least, Lower, NullIf, StrIndex from django.http import JsonResponse @@ -126,7 +126,6 @@ def communes_autocomplete(request): return JsonResponse({"results": communes}, safe=False) -@login_required @check_user(is_allowed_to_use_gps_advanced_features) def gps_users_autocomplete(request): """ diff --git a/itou/www/companies_views/views.py b/itou/www/companies_views/views.py index 9b1efa4dcf..266152e122 100644 --- a/itou/www/companies_views/views.py +++ b/itou/www/companies_views/views.py @@ -3,7 +3,7 @@ from django.conf import settings from django.contrib import messages -from django.contrib.auth.decorators import login_not_required, login_required +from django.contrib.auth.decorators import login_not_required from django.core.cache import caches from django.core.exceptions import PermissionDenied from django.db.models import Count, Q @@ -110,7 +110,6 @@ def report_tally_url(user, company, job_description=None): ### Main company view -@login_required def overview(request, template_name="companies/overview.html"): company = get_current_company_or_404(request) @@ -170,7 +169,6 @@ def get_context_data(self, **kwargs): } -@login_required def job_description_list(request, template_name="companies/job_description_list.html"): company = get_current_company_or_404(request) job_descriptions = ( @@ -268,7 +266,6 @@ def _get_job_description(session_data): return None -@login_required def edit_job_description(request, template_name="companies/edit_job_description.html"): company = get_current_company_or_404(request) session_data = request.session.get(ITOU_SESSION_JOB_DESCRIPTION_KEY) or {} @@ -285,7 +282,6 @@ def edit_job_description(request, template_name="companies/edit_job_description. return render(request, template_name, {"form": form}) -@login_required def edit_job_description_details(request, template_name="companies/edit_job_description_details.html"): company = get_current_company_or_404(request) session_data = request.session.get(ITOU_SESSION_JOB_DESCRIPTION_KEY) @@ -318,7 +314,6 @@ def edit_job_description_details(request, template_name="companies/edit_job_desc return render(request, template_name, context) -@login_required def edit_job_description_preview(request, template_name="companies/edit_job_description_preview.html"): company = get_current_company_or_404(request) session_data = request.session.get(ITOU_SESSION_JOB_DESCRIPTION_KEY) @@ -359,7 +354,6 @@ def edit_job_description_preview(request, template_name="companies/edit_job_desc return render(request, template_name, context) -@login_required def update_job_description(request, job_description_id): request.session[ITOU_SESSION_JOB_DESCRIPTION_KEY] = {"pk": job_description_id} return HttpResponseRedirect(reverse("companies_views:edit_job_description")) @@ -368,7 +362,6 @@ def update_job_description(request, job_description_id): ### Financial annexes views -@login_required def show_financial_annexes(request, template_name="companies/show_financial_annexes.html"): """ Show a summary of the financial annexes of the convention to the siae admin user. Financial annexes are grouped @@ -413,7 +406,6 @@ def show_financial_annexes(request, template_name="companies/show_financial_anne return render(request, template_name, context) -@login_required def select_financial_annex(request, template_name="companies/select_financial_annex.html"): """ Let siae admin user select a new convention via a financial annex number. @@ -498,7 +490,6 @@ def get_context_data(self, **kwargs): } -@login_required def create_company(request, template_name="companies/create_siae.html"): current_compny = get_current_company_or_404(request) if not request.user.can_create_siae_antenna(parent_siae=current_compny): @@ -523,7 +514,6 @@ def create_company(request, template_name="companies/create_siae.html"): return render(request, template_name, context) -@login_required def edit_company_step_contact_infos(request, template_name="companies/edit_siae.html"): if ITOU_SESSION_EDIT_COMPANY_KEY not in request.session: request.session[ITOU_SESSION_EDIT_COMPANY_KEY] = {} @@ -552,7 +542,6 @@ def edit_company_step_contact_infos(request, template_name="companies/edit_siae. return render(request, template_name, context) -@login_required def edit_company_step_description(request, template_name="companies/edit_siae_description.html"): if ITOU_SESSION_EDIT_COMPANY_KEY not in request.session: return HttpResponseRedirect(reverse("companies_views:edit_company_step_contact_infos")) @@ -574,7 +563,6 @@ def edit_company_step_description(request, template_name="companies/edit_siae_de return render(request, template_name, context) -@login_required def edit_company_step_preview(request, template_name="companies/edit_siae_preview.html"): if ITOU_SESSION_EDIT_COMPANY_KEY not in request.session: return HttpResponseRedirect(reverse("companies_views:edit_company_step_contact_infos")) @@ -624,7 +612,6 @@ def edit_company_step_preview(request, template_name="companies/edit_siae_previe ### Company memberships views -@login_required def members(request, template_name="companies/members.html"): company = get_current_company_or_404(request) if not company.is_active: @@ -648,7 +635,6 @@ def members(request, template_name="companies/members.html"): return render(request, template_name, context) -@login_required def deactivate_member(request, user_id, template_name="companies/deactivate_member.html"): company = get_current_company_or_404(request) target_member = User.objects.get(pk=user_id) @@ -664,7 +650,6 @@ def deactivate_member(request, user_id, template_name="companies/deactivate_memb return render(request, template_name, context) -@login_required def update_admin_role(request, action, user_id, template_name="companies/update_admins.html"): company = get_current_company_or_404(request) target_member = User.objects.get(pk=user_id) diff --git a/itou/www/dashboard/views.py b/itou/www/dashboard/views.py index 63efb068af..9eece92ce9 100644 --- a/itou/www/dashboard/views.py +++ b/itou/www/dashboard/views.py @@ -4,7 +4,6 @@ from django.conf import settings from django.contrib import auth, messages from django.contrib.auth import REDIRECT_FIELD_NAME -from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.db.models import F from django.http import Http404, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect @@ -106,7 +105,6 @@ def _employer_dashboard_context(request): } -@login_required def dashboard(request, template_name="dashboard/dashboard.html"): context = { "active_geiq_campaign": None, @@ -158,7 +156,6 @@ def dashboard(request, template_name="dashboard/dashboard.html"): return render(request, template_name, context) -@login_required def dashboard_stats(request, template_name="dashboard/dashboard_stats.html"): if not stats_utils.can_view_stats_dashboard_widget(request): return HttpResponseForbidden() @@ -205,10 +202,9 @@ class ItouPasswordChangeView(PasswordChangeView): success_url = reverse_lazy("dashboard:index") -password_change = login_required(ItouPasswordChangeView.as_view()) +password_change = ItouPasswordChangeView.as_view() -@login_required def edit_user_email(request, template_name="dashboard/edit_user_email.html"): if request.user.has_sso_provider: return HttpResponseForbidden() @@ -227,7 +223,6 @@ def edit_user_email(request, template_name="dashboard/edit_user_email.html"): return render(request, template_name, context) -@login_required def edit_user_info(request, template_name="dashboard/edit_user_info.html"): """ Edit a user. @@ -281,7 +276,6 @@ def edit_user_info(request, template_name="dashboard/edit_user_info.html"): return render(request, template_name, context) -@login_required def edit_job_seeker_info(request, job_seeker_public_id, template_name="dashboard/edit_job_seeker_info.html"): job_seeker = get_object_or_404( User.objects.filter(kind=UserKind.JOB_SEEKER).select_related("jobseeker_profile"), @@ -318,7 +312,6 @@ def edit_job_seeker_info(request, job_seeker_public_id, template_name="dashboard return render(request, template_name, context) -@login_required @require_POST def switch_organization(request): try: @@ -337,7 +330,6 @@ def switch_organization(request): return HttpResponseRedirect(reverse("dashboard:index")) -@login_required def edit_user_notifications(request, template_name="dashboard/edit_user_notifications.html"): if request.user.is_staff: raise Http404("L'utilisateur admin ne peut gérer ses notifications.") @@ -367,7 +359,6 @@ def edit_user_notifications(request, template_name="dashboard/edit_user_notifica return render(request, template_name, context) -@login_required def api_token(request, template_name="dashboard/api_token.html"): if not (request.user.is_employer and request.is_current_organization_admin): raise PermissionDenied diff --git a/itou/www/employee_record_views/views.py b/itou/www/employee_record_views/views.py index c51e42ec54..91dbed8c38 100644 --- a/itou/www/employee_record_views/views.py +++ b/itou/www/employee_record_views/views.py @@ -1,5 +1,4 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied, ValidationError from django.db.models import Count from django.http.response import HttpResponseRedirect @@ -142,7 +141,6 @@ def done(self, form_list, *args, **kwargs): ) -@login_required @require_safe def list_employee_records(request, template_name="employee_record/list.html"): siae = get_current_company_or_404(request) @@ -218,7 +216,6 @@ def list_employee_records(request, template_name="employee_record/list.html"): return render(request, "employee_record/includes/list_results.html" if request.htmx else template_name, context) -@login_required def create(request, job_application_id, template_name="employee_record/create.html"): """ Create a new employee record from a given job application @@ -247,7 +244,6 @@ def create(request, job_application_id, template_name="employee_record/create.ht return render(request, template_name, context) -@login_required def create_step_2(request, job_application_id, template_name="employee_record/create.html"): """ Create a new employee record from a given job application @@ -301,7 +297,6 @@ def create_step_2(request, job_application_id, template_name="employee_record/cr return render(request, template_name, context) -@login_required def create_step_3(request, job_application_id, template_name="employee_record/create.html"): """ Create a new employee record from a given job application @@ -364,7 +359,6 @@ def create_step_3(request, job_application_id, template_name="employee_record/cr return render(request, template_name, context) -@login_required def create_step_4(request, job_application_id, template_name="employee_record/create.html"): """ Create a new employee record from a given job application @@ -401,7 +395,6 @@ def create_step_4(request, job_application_id, template_name="employee_record/cr return render(request, template_name, context) -@login_required def create_step_5(request, job_application_id, template_name="employee_record/create.html"): """ Create a new employee record from a given job application @@ -440,7 +433,6 @@ def create_step_5(request, job_application_id, template_name="employee_record/cr return render(request, template_name, context) -@login_required def summary(request, employee_record_id, template_name="employee_record/summary.html"): siae = get_current_company_or_404(request) @@ -462,7 +454,6 @@ def summary(request, employee_record_id, template_name="employee_record/summary. return render(request, template_name, context) -@login_required def disable(request, employee_record_id, template_name="employee_record/disable.html"): siae = get_current_company_or_404(request) @@ -493,7 +484,6 @@ def disable(request, employee_record_id, template_name="employee_record/disable. return render(request, template_name, context) -@login_required def reactivate(request, employee_record_id, template_name="employee_record/reactivate.html"): siae = get_current_company_or_404(request) diff --git a/itou/www/geiq_views/views.py b/itou/www/geiq_views/views.py index d8755e8f05..2330c763eb 100644 --- a/itou/www/geiq_views/views.py +++ b/itou/www/geiq_views/views.py @@ -3,7 +3,6 @@ import logging from django.contrib import messages -from django.contrib.auth.decorators import login_required from django.core.exceptions import ImproperlyConfigured from django.core.files.storage import default_storage from django.db.models import Count, F, OuterRef, Prefetch, Q, Subquery, Sum @@ -65,7 +64,6 @@ def _get_assessments_for_labor_inspector(request): ) -@login_required @check_user(lambda user: user.is_active and (user.is_employer or user.is_labor_inspector)) def assessment_info(request, assessment_pk): if request.user.is_employer: @@ -131,7 +129,6 @@ def _assessment_info_for_labor_inspector( return render(request, template_name, context) -@login_required @check_user(lambda user: user.is_active and user.is_labor_inspector) def assessment_review(request, assessment_pk, template_name="geiq/assessment_review.html"): assessment = get_object_or_404(_get_assessments_for_labor_inspector(request), pk=assessment_pk) @@ -154,7 +151,6 @@ def assessment_review(request, assessment_pk, template_name="geiq/assessment_rev return render(request, template_name, context) -@login_required @check_user(lambda user: user.is_active and (user.is_employer or user.is_labor_inspector)) def employee_list(request, assessment_pk, info_type): try: @@ -248,7 +244,6 @@ def _lock_assessment_and_sync(assessment): return True -@login_required @require_POST @check_user(lambda user: user.is_active and user.is_employer) def label_sync(request, assessment_pk): @@ -268,7 +263,6 @@ def label_sync(request, assessment_pk): return render(request, "geiq/includes/last_synced_at.html", context) -@login_required @require_safe @check_user(lambda user: user.is_active and (user.is_employer or user.is_labor_inspector)) def employee_details(request, employee_pk): @@ -297,7 +291,6 @@ def employee_details(request, employee_pk): return render(request, "geiq/employee_details.html", context) -@login_required @check_user(lambda user: user.is_active and user.is_labor_inspector) def geiq_list(request, institution_pk, year=None, template_name="geiq/geiq_list.html"): institution = get_object_or_404( @@ -336,7 +329,6 @@ def geiq_list(request, institution_pk, year=None, template_name="geiq/geiq_list. @require_safe -@login_required @check_user(lambda user: user.is_active and (user.is_employer or user.is_labor_inspector)) def assessment_report(request, assessment_pk): if request.user.is_labor_inspector: diff --git a/itou/www/gps/views.py b/itou/www/gps/views.py index a4cdd5799f..f92a8ada7e 100644 --- a/itou/www/gps/views.py +++ b/itou/www/gps/views.py @@ -1,4 +1,3 @@ -from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from django.db.models import Count @@ -23,7 +22,6 @@ def is_allowed_to_use_gps_advanced_features(user): return user.is_employer or user.is_prescriber_with_authorized_org -@login_required @check_user(is_allowed_to_use_gps) def my_groups(request, template_name="gps/my_groups.html"): memberships = ( @@ -51,7 +49,6 @@ def my_groups(request, template_name="gps/my_groups.html"): return render(request, "gps/includes/memberships_results.html" if request.htmx else template_name, context) -@login_required @check_user(is_allowed_to_use_gps_advanced_features) def join_group(request, template_name="gps/join_group.html"): form = GpsUserSearchForm(data=request.POST or None) @@ -75,7 +72,6 @@ def join_group(request, template_name="gps/join_group.html"): return render(request, template_name, context) -@login_required @check_user(is_allowed_to_use_gps) def leave_group(request, group_id): membership = ( @@ -89,7 +85,6 @@ def leave_group(request, group_id): return HttpResponseRedirect(reverse("gps:my_groups")) -@login_required @check_user(is_allowed_to_use_gps) def toggle_referent(request, group_id): membership = ( diff --git a/itou/www/institutions_views/views.py b/itou/www/institutions_views/views.py index e6fe2e2167..1948515cde 100644 --- a/itou/www/institutions_views/views.py +++ b/itou/www/institutions_views/views.py @@ -1,4 +1,3 @@ -from django.contrib.auth.decorators import login_required from django.db.models import Count, Q from django.http import HttpResponseRedirect from django.shortcuts import render @@ -9,7 +8,6 @@ from itou.utils.perms.institution import get_current_institution_or_404 -@login_required def member_list(request, template_name="institutions/members.html"): """ List members of an institution. @@ -39,7 +37,6 @@ def member_list(request, template_name="institutions/members.html"): return render(request, template_name, context) -@login_required def deactivate_member(request, user_id, template_name="institutions/deactivate_member.html"): institution = get_current_institution_or_404(request) target_member = User.objects.get(pk=user_id) @@ -55,7 +52,6 @@ def deactivate_member(request, user_id, template_name="institutions/deactivate_m return render(request, template_name, context) -@login_required def update_admin_role(request, action, user_id, template_name="institutions/update_admins.html"): institution = get_current_institution_or_404(request) target_member = User.objects.get(pk=user_id) diff --git a/itou/www/invitations_views/views.py b/itou/www/invitations_views/views.py index 740c11b910..e5aa2fed74 100644 --- a/itou/www/invitations_views/views.py +++ b/itou/www/invitations_views/views.py @@ -3,7 +3,7 @@ from allauth.account.adapter import get_adapter from django.conf import settings from django.contrib import messages -from django.contrib.auth.decorators import login_not_required, login_required +from django.contrib.auth.decorators import login_not_required from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect, render, reverse from django.utils import formats, safestring @@ -121,7 +121,6 @@ def new_user(request, invitation_type, invitation_id): return handle_registration(request, invitation, invitation_type) -@login_required def invite_prescriber_with_org(request, template_name="invitations_views/create.html"): organization = get_current_org_or_404(request) form_kwargs = {"sender": request.user, "organization": organization} @@ -180,7 +179,6 @@ def invite_prescriber_with_org(request, template_name="invitations_views/create. return render(request, template_name, context) -@login_required def join_prescriber_organization(request, invitation_id): invitation = get_object_or_404(PrescriberWithOrgInvitation, pk=invitation_id) handle_prescriber_intivation(invitation, request) @@ -189,7 +187,6 @@ def join_prescriber_organization(request, invitation_id): return HttpResponseRedirect(url) -@login_required def invite_employer(request, template_name="invitations_views/create.html"): form_post_url = reverse("invitations_views:invite_employer") back_url = reverse("companies_views:members") @@ -214,7 +211,6 @@ def invite_employer(request, template_name="invitations_views/create.html"): return render(request, template_name, context) -@login_required def join_company(request, invitation_id): invitation = get_object_or_404(EmployerInvitation, pk=invitation_id) handle_employer_invitation(invitation, request) @@ -223,7 +219,6 @@ def join_company(request, invitation_id): return HttpResponseRedirect(url) -@login_required def invite_labor_inspector(request, template_name="invitations_views/create.html"): institution = get_current_institution_or_404(request) form_kwargs = {"sender": request.user, "institution": institution} @@ -264,7 +259,6 @@ def invite_labor_inspector(request, template_name="invitations_views/create.html return render(request, template_name, context) -@login_required def join_institution(request, invitation_id): invitation = get_object_or_404(LaborInspectorInvitation, pk=invitation_id) handle_labor_inspector_invitation(invitation, request) diff --git a/itou/www/itou_staff_views/views.py b/itou/www/itou_staff_views/views.py index 8c35147d9a..2418c43f06 100644 --- a/itou/www/itou_staff_views/views.py +++ b/itou/www/itou_staff_views/views.py @@ -4,7 +4,6 @@ from dateutil.relativedelta import relativedelta from django.contrib import messages -from django.contrib.auth.decorators import login_required from django.db.models import Q from django.http import FileResponse, HttpResponseRedirect, StreamingHttpResponse from django.shortcuts import get_object_or_404, render @@ -38,7 +37,6 @@ def write(self, value): return value -@login_required @check_user(lambda user: user.is_superuser) def export_job_applications_unknown_to_ft( request, @@ -111,7 +109,6 @@ def content(): return render(request, template_name, {"form": form}) -@login_required @check_user(lambda user: user.is_superuser) def export_ft_api_rejections(request): first_day_of_month = timezone.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0) @@ -174,7 +171,6 @@ def export_ft_api_rejections(request): ) -@login_required @check_user(lambda user: user.is_superuser) def export_cta(request): employees_qs = CompanyMembership.objects.active().select_related("company", "user") @@ -200,7 +196,6 @@ def content(): ) -@login_required @check_user(lambda user: user.is_superuser) def merge_users(request, template_name="itou_staff_views/merge_users.html"): form = MergeUserForm(data=request.POST or None) @@ -216,7 +211,6 @@ def merge_users(request, template_name="itou_staff_views/merge_users.html"): return render(request, template_name, {"form": form}) -@login_required @check_user(lambda user: user.is_superuser) def merge_users_confirm(request, user_1_pk, user_2_pk, template_name="itou_staff_views/merge_users_confirm.html"): ALLOWED_USER_KINDS = [UserKind.PRESCRIBER, UserKind.EMPLOYER] diff --git a/itou/www/prescribers_views/views.py b/itou/www/prescribers_views/views.py index b712848e97..ad0e2fd4cf 100644 --- a/itou/www/prescribers_views/views.py +++ b/itou/www/prescribers_views/views.py @@ -1,5 +1,5 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_not_required, login_required +from django.contrib.auth.decorators import login_not_required from django.core.exceptions import PermissionDenied from django.db.models import Count, Q from django.http import HttpResponseRedirect @@ -28,7 +28,6 @@ def card(request, org_id, template_name="prescribers/card.html"): return render(request, template_name, context) -@login_required def edit_organization(request, template_name="prescribers/edit_organization.html"): organization = get_current_org_or_404(request) if not organization.has_admin(request.user): @@ -48,7 +47,6 @@ def edit_organization(request, template_name="prescribers/edit_organization.html return render(request, template_name, context) -@login_required def member_list(request, template_name="prescribers/members.html"): """ List members of a prescriber organization. @@ -74,7 +72,6 @@ def member_list(request, template_name="prescribers/members.html"): return render(request, template_name, context) -@login_required def deactivate_member(request, user_id, template_name="prescribers/deactivate_member.html"): organization = get_current_org_or_404(request) target_member = User.objects.get(pk=user_id) @@ -90,7 +87,6 @@ def deactivate_member(request, user_id, template_name="prescribers/deactivate_me return render(request, template_name, context) -@login_required def update_admin_role(request, action, user_id, template_name="prescribers/update_admins.html"): organization = get_current_org_or_404(request) target_member = User.objects.get(pk=user_id) @@ -107,7 +103,6 @@ def update_admin_role(request, action, user_id, template_name="prescribers/updat return render(request, template_name, context) -@login_required def list_accredited_organizations(request, template_name="prescribers/list_accredited_organizations.html"): """ List organizations accredited by a departmental council ("Conseil Départemental"). diff --git a/itou/www/siae_evaluations_views/views.py b/itou/www/siae_evaluations_views/views.py index 18079d351c..49600050a4 100644 --- a/itou/www/siae_evaluations_views/views.py +++ b/itou/www/siae_evaluations_views/views.py @@ -1,5 +1,5 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_not_required, login_required +from django.contrib.auth.decorators import login_not_required from django.core.files.storage import default_storage from django.db.models import Q from django.http import Http404, HttpResponseForbidden, HttpResponseRedirect @@ -37,7 +37,6 @@ ) -@login_required @check_user(lambda user: user.is_labor_inspector) def samples_selection(request, template_name="siae_evaluations/samples_selection.html"): institution = get_current_institution_or_404(request) @@ -72,7 +71,6 @@ def samples_selection(request, template_name="siae_evaluations/samples_selection return render(request, template_name, context) -@login_required def campaign_calendar(request, evaluation_campaign_pk, template_name="siae_evaluations/campaign_calendar.html"): evaluation_campaign = get_object_or_404( EvaluationCampaign, @@ -86,7 +84,6 @@ def campaign_calendar(request, evaluation_campaign_pk, template_name="siae_evalu return render(request, template_name, context) -@login_required @check_user(lambda user: user.is_labor_inspector) def institution_evaluated_siae_list( request, evaluation_campaign_pk, template_name="siae_evaluations/institution_evaluated_siae_list.html" @@ -118,7 +115,6 @@ def institution_evaluated_siae_list( return render(request, template_name, context) -@login_required @check_user(lambda user: user.is_labor_inspector or user.is_employer) def evaluated_siae_detail(request, evaluated_siae_pk, template_name="siae_evaluations/evaluated_siae_detail.html"): owner_data = {} @@ -346,7 +342,6 @@ def get_success_url(self): ) -@login_required @check_user(lambda user: user.is_labor_inspector or user.is_employer) def evaluated_siae_sanction(request, evaluated_siae_pk, viewer_type): allowed_viewers = { @@ -374,7 +369,6 @@ def evaluated_siae_sanction(request, evaluated_siae_pk, viewer_type): return render(request, "siae_evaluations/evaluated_siae_sanction.html", context) -@login_required def evaluated_job_application( request, evaluated_job_application_pk, template_name="siae_evaluations/evaluated_job_application.html" ): @@ -454,7 +448,6 @@ def evaluated_job_application( return render(request, template_name, context) -@login_required @require_POST def institution_evaluated_administrative_criteria(request, evaluated_administrative_criteria_pk, action): institution = get_current_institution_or_404(request) @@ -486,7 +479,6 @@ def institution_evaluated_administrative_criteria(request, evaluated_administrat ) -@login_required @require_POST def institution_evaluated_siae_validation(request, evaluated_siae_pk): institution = get_current_institution_or_404(request) @@ -519,7 +511,6 @@ def institution_evaluated_siae_validation(request, evaluated_siae_pk): ) -@login_required def siae_job_applications_list( request, evaluated_siae_pk, @@ -555,7 +546,6 @@ def siae_job_applications_list( return render(request, template_name, context) -@login_required def siae_select_criteria( request, evaluated_job_application_pk, template_name="siae_evaluations/siae_select_criteria.html" ): @@ -628,7 +618,6 @@ def siae_select_criteria( return render(request, template_name, context) -@login_required def siae_upload_doc( request, evaluated_administrative_criteria_pk, template_name="siae_evaluations/siae_upload_doc.html" ): @@ -676,7 +665,6 @@ def siae_upload_doc( return render(request, template_name, context) -@login_required @require_POST def siae_submit_proofs(request, evaluated_siae_pk): evaluated_siae = get_object_or_404( @@ -723,7 +711,6 @@ def siae_submit_proofs(request, evaluated_siae_pk): return HttpResponseRedirect(back_url) -@login_required @require_safe def view_proof(request, evaluated_administrative_criteria_id): if request.user.is_employer: diff --git a/itou/www/signup/views.py b/itou/www/signup/views.py index 7eb7ab37d4..6def083d1f 100644 --- a/itou/www/signup/views.py +++ b/itou/www/signup/views.py @@ -9,7 +9,7 @@ from django.conf import settings from django.contrib import auth, messages from django.contrib.auth import REDIRECT_FIELD_NAME, login -from django.contrib.auth.decorators import login_not_required, login_required +from django.contrib.auth.decorators import login_not_required from django.core.exceptions import PermissionDenied from django.db import Error, transaction from django.http import HttpResponseRedirect @@ -764,7 +764,6 @@ def prescriber_user(request, template_name="signup/prescriber_user.html"): @valid_prescriber_signup_session_required @push_url_in_history(global_constants.ITOU_SESSION_PRESCRIBER_SIGNUP_KEY) -@login_required def prescriber_join_org(request): """ User is redirected here after a successful oauth signup. diff --git a/itou/www/stats/views.py b/itou/www/stats/views.py index 0b6d5406a0..2312755898 100644 --- a/itou/www/stats/views.py +++ b/itou/www/stats/views.py @@ -15,7 +15,7 @@ """ from django.conf import settings -from django.contrib.auth.decorators import login_not_required, login_required +from django.contrib.auth.decorators import login_not_required from django.core.exceptions import PermissionDenied from django.http import HttpResponseNotFound, HttpResponseRedirect from django.shortcuts import render @@ -187,7 +187,6 @@ def stats_public(request): return render_stats(request=request, context=context) -@login_required def stats_redirect(request, dashboard_name): match request.user.kind: case UserKind.LABOR_INSPECTOR: @@ -198,7 +197,6 @@ def stats_redirect(request, dashboard_name): return HttpResponseRedirect(reverse(f"stats:stats_{normalized_organization_kind}_{dashboard_name}")) -@login_required def stats_siae_aci(request): """ ACI stats shown to their own members. @@ -219,7 +217,6 @@ def stats_siae_aci(request): ) -@login_required def stats_siae_etp(request): """ SIAE stats shown to their own members. @@ -247,7 +244,6 @@ def stats_siae_etp(request): ) -@login_required def stats_siae_orga_etp(request): """ SIAE stats shown to their own members. @@ -295,22 +291,18 @@ def render_stats_siae(request, page_title): ) -@login_required def stats_siae_hiring(request): return render_stats_siae(request=request, page_title="Données de candidatures de mes structures") -@login_required def stats_siae_auto_prescription(request): return render_stats_siae(request=request, page_title="Focus auto-prescription") -@login_required def stats_siae_follow_siae_evaluation(request): return render_stats_siae(request=request, page_title="Suivi du contrôle a posteriori") -@login_required def stats_siae_hiring_report(request): return render_stats_siae(request=request, page_title="Déclaration d’embauche") @@ -335,22 +327,18 @@ def render_stats_cd(request, page_title, *, params=None, extra_context=None): return render_stats(request=request, context=context, params=params) -@login_required def stats_cd_iae(request): return render_stats_cd(request=request, page_title="Données IAE") -@login_required def stats_cd_hiring(request): return render_stats_cd(request=request, page_title="Facilitation des embauches en IAE") -@login_required def stats_cd_brsa(request): return render_stats_cd(request=request, page_title="Suivi des prescriptions des accompagnateurs des publics bRSA") -@login_required def stats_cd_aci(request): current_org = get_current_org_or_404(request) if not utils.can_view_stats_cd_aci(request): @@ -363,7 +351,6 @@ def stats_cd_aci(request): ) -@login_required() def stats_cd_orga_etp(request): get_current_org_or_404(request) if not utils.can_view_stats_cd_orga_etp(request): @@ -421,7 +408,6 @@ def render_stats_ft(request, page_title, extra_params=None): return render_stats(request=request, context=context, params=params) -@login_required def stats_ft_delay_main(request): return render_stats_ft( request=request, @@ -432,7 +418,6 @@ def stats_ft_delay_main(request): ) -@login_required def stats_ft_delay_raw(request): return render_stats_ft( request=request, @@ -441,7 +426,6 @@ def stats_ft_delay_raw(request): ) -@login_required def stats_ft_conversion_main(request): return render_stats_ft( request=request, @@ -452,7 +436,6 @@ def stats_ft_conversion_main(request): ) -@login_required def stats_ft_conversion_raw(request): return render_stats_ft( request=request, @@ -463,7 +446,6 @@ def stats_ft_conversion_raw(request): ) -@login_required def stats_ft_state_main(request): return render_stats_ft( request=request, @@ -474,7 +456,6 @@ def stats_ft_state_main(request): ) -@login_required def stats_ft_state_raw(request): return render_stats_ft( request=request, @@ -485,7 +466,6 @@ def stats_ft_state_raw(request): ) -@login_required def stats_ft_tension(request): return render_stats_ft( request=request, @@ -515,7 +495,6 @@ def render_stats_ph(request, page_title, *, extra_params=None, extra_context=Non return render_stats(request=request, context=context, params=params) -@login_required def stats_ph_state_main(request): if not utils.can_view_stats_ph(request): raise PermissionDenied @@ -576,37 +555,30 @@ def render_stats_ddets_iae(request, page_title, extra_context=None, extend_stats ) -@login_required def stats_ddets_iae_auto_prescription(request): return render_stats_ddets_iae(request=request, page_title="Focus auto-prescription") -@login_required def stats_ddets_iae_ph_prescription(request): return render_stats_ddets_iae(request=request, page_title="Suivi des prescriptions des prescripteurs habilités") -@login_required def stats_ddets_iae_follow_siae_evaluation(request): return render_stats_ddets_iae(request=request, page_title="Suivi du contrôle à posteriori") -@login_required def stats_ddets_iae_follow_prolongation(request): return render_stats_ddets_iae(request=request, page_title="Suivi des demandes de prolongation") -@login_required def stats_ddets_iae_tension(request): return render_stats_ddets_iae(request=request, page_title="SIAE qui peinent à recruter sur le territoire") -@login_required def stats_ddets_iae_iae(request): return render_stats_ddets_iae(request=request, page_title="Données IAE de mon département") -@login_required def stats_ddets_iae_siae_evaluation(request): extra_context = { "back_url": reverse("siae_evaluations_views:samples_selection"), @@ -617,7 +589,6 @@ def stats_ddets_iae_siae_evaluation(request): ) -@login_required def stats_ddets_iae_hiring(request): return render_stats_ddets_iae( request=request, @@ -625,7 +596,6 @@ def stats_ddets_iae_hiring(request): ) -@login_required def stats_ddets_iae_state(request): return render_stats_ddets_iae( request=request, @@ -634,7 +604,6 @@ def stats_ddets_iae_state(request): ) -@login_required def stats_ddets_iae_aci(request): current_org = get_current_institution_or_404(request) if not utils.can_view_stats_ddets_iae_aci(request): @@ -647,7 +616,6 @@ def stats_ddets_iae_aci(request): ) -@login_required def stats_ddets_iae_orga_etp(request): if not utils.can_view_stats_ddets_iae_orga_etp(request): raise PermissionDenied @@ -670,7 +638,6 @@ def render_stats_ddets_log(request, page_title, extend_stats_to_whole_region): ) -@login_required def stats_ddets_log_state(request): return render_stats_ddets_log( request=request, @@ -691,32 +658,26 @@ def render_stats_dreets_iae(request, page_title, *, extra_context=None): return render_stats(request=request, context=context, params=params) -@login_required def stats_dreets_iae_auto_prescription(request): return render_stats_dreets_iae(request=request, page_title="Focus auto-prescription") -@login_required def stats_dreets_iae_ph_prescription(request): return render_stats_dreets_iae(request=request, page_title="Suivi des prescriptions des prescripteurs habilités") -@login_required def stats_dreets_iae_follow_siae_evaluation(request): return render_stats_dreets_iae(request=request, page_title="Suivi du contrôle à posteriori") -@login_required def stats_dreets_iae_follow_prolongation(request): return render_stats_dreets_iae(request=request, page_title="Suivi des demandes de prolongation") -@login_required def stats_dreets_iae_tension(request): return render_stats_dreets_iae(request=request, page_title="SIAE qui peinent à recruter sur le territoire") -@login_required def stats_dreets_iae_iae(request): return render_stats_dreets_iae( request=request, @@ -724,7 +685,6 @@ def stats_dreets_iae_iae(request): ) -@login_required def stats_dreets_iae_hiring(request): return render_stats_dreets_iae( request=request, @@ -732,7 +692,6 @@ def stats_dreets_iae_hiring(request): ) -@login_required def stats_dreets_iae_state(request): return render_stats_dreets_iae( request=request, @@ -740,7 +699,6 @@ def stats_dreets_iae_state(request): ) -@login_required def stats_dreets_iae_orga_etp(request): if not utils.can_view_stats_dreets_iae_orga_etp(request): raise PermissionDenied @@ -764,28 +722,24 @@ def render_stats_dgefp_iae(request, page_title, extra_params=None, extra_context return render_stats(request=request, context=context, params=extra_params) -@login_required def stats_dgefp_iae_auto_prescription(request): return render_stats_dgefp_iae( request=request, page_title="Focus auto-prescription", extra_params=get_params_for_whole_country() ) -@login_required def stats_dgefp_iae_follow_siae_evaluation(request): return render_stats_dgefp_iae( request=request, page_title="Suivi du contrôle à posteriori", extra_params=get_params_for_whole_country() ) -@login_required def stats_dgefp_iae_follow_prolongation(request): return render_stats_dgefp_iae( request=request, page_title="Suivi des demandes de prolongation", extra_params=get_params_for_whole_country() ) -@login_required def stats_dgefp_iae_tension(request): return render_stats_dgefp_iae( request=request, @@ -794,14 +748,12 @@ def stats_dgefp_iae_tension(request): ) -@login_required def stats_dgefp_iae_hiring(request): return render_stats_dgefp_iae( request=request, page_title="Données facilitation de l'embauche", extra_params=get_params_for_whole_country() ) -@login_required def stats_dgefp_iae_state(request): return render_stats_dgefp_iae( request=request, @@ -810,14 +762,12 @@ def stats_dgefp_iae_state(request): ) -@login_required def stats_dgefp_iae_iae(request): return render_stats_dgefp_iae( request=request, page_title="Données des régions", extra_params=get_params_for_whole_country() ) -@login_required def stats_dgefp_iae_ph_prescription(request): return render_stats_dgefp_iae( request=request, @@ -826,7 +776,6 @@ def stats_dgefp_iae_ph_prescription(request): ) -@login_required def stats_dgefp_iae_siae_evaluation(request): return render_stats_dgefp_iae( request=request, @@ -836,12 +785,10 @@ def stats_dgefp_iae_siae_evaluation(request): ) -@login_required def stats_dgefp_iae_af(request): return render_stats_dgefp_iae(request=request, page_title="Annexes financières actives") -@login_required def stats_dgefp_iae_orga_etp(request): return render_stats_dgefp_iae( request=request, @@ -850,7 +797,6 @@ def stats_dgefp_iae_orga_etp(request): ) -@login_required def stats_dihal_state(request): get_current_institution_or_404(request) if not utils.can_view_stats_dihal(request): @@ -861,7 +807,6 @@ def stats_dihal_state(request): return render_stats(request=request, context=context, params=get_params_for_whole_country()) -@login_required def stats_drihl_state(request): get_current_institution_or_404(request) if not utils.can_view_stats_drihl(request): @@ -872,7 +817,6 @@ def stats_drihl_state(request): return render_stats(request=request, context=context, params=get_params_for_idf_region()) -@login_required def stats_iae_network_hiring(request): current_org = get_current_institution_or_404(request) if not utils.can_view_stats_iae_network(request): @@ -887,7 +831,6 @@ def stats_iae_network_hiring(request): ) -@login_required def stats_convergence_prescription(request): get_current_institution_or_404(request) if not utils.can_view_stats_convergence(request): @@ -900,7 +843,6 @@ def stats_convergence_prescription(request): ) -@login_required def stats_convergence_job_application(request): get_current_institution_or_404(request) if not utils.can_view_stats_convergence(request): @@ -913,7 +855,6 @@ def stats_convergence_job_application(request): ) -@login_required def stats_staff_service_indicators(request): """Indicator statistics for Les Emplois staff""" if not utils.can_view_stats_staff(request): diff --git a/itou/www/welcoming_tour/views.py b/itou/www/welcoming_tour/views.py index 645f33aed6..fc9d8525dc 100644 --- a/itou/www/welcoming_tour/views.py +++ b/itou/www/welcoming_tour/views.py @@ -1,8 +1,6 @@ -from django.contrib.auth.decorators import login_required from django.shortcuts import render -@login_required def index(request): user = request.user template_name = "welcoming_tour/job_seeker.html" From 75921b9a7d8366c7fb6fe1833d9be7d583ba2734 Mon Sep 17 00:00:00 2001 From: Xavier Fernandez Date: Tue, 7 Jan 2025 10:46:40 +0100 Subject: [PATCH 4/4] www.dashboard: avoid extra variable --- config/urls.py | 2 +- itou/www/dashboard/views.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/config/urls.py b/config/urls.py index a9966568be..45b075f62b 100644 --- a/config/urls.py +++ b/config/urls.py @@ -35,7 +35,7 @@ # Override allauth `account_change_password` URL. # /accounts/password/change/ <=> account_change_password # https://github.com/pennersr/django-allauth/issues/468 - re_path(r"^accounts/password/change/$", dashboard_views.password_change), + re_path(r"^accounts/password/change/$", dashboard_views.ItouPasswordChangeView.as_view()), # -------------------------------------------------------------------------------------- # Override allauth `account_reset_password` URL. # Avoid user enumeration via password reset page. diff --git a/itou/www/dashboard/views.py b/itou/www/dashboard/views.py index 9eece92ce9..16799dbde8 100644 --- a/itou/www/dashboard/views.py +++ b/itou/www/dashboard/views.py @@ -202,9 +202,6 @@ class ItouPasswordChangeView(PasswordChangeView): success_url = reverse_lazy("dashboard:index") -password_change = ItouPasswordChangeView.as_view() - - def edit_user_email(request, template_name="dashboard/edit_user_email.html"): if request.user.has_sso_provider: return HttpResponseForbidden()