(plugins) add endpoint to list SIRET of active organizations

Allow access to AccountService with right scope to list
SIRET of active communes
This commit is contained in:
Sabrina Demagny
2025-03-31 14:18:42 +02:00
parent 855e20d407
commit 594d3af0d0
8 changed files with 174 additions and 0 deletions

View File

@@ -10,6 +10,7 @@ and this project adheres to
### Added
- ✨(plugins) add endpoint to list siret of active organizations #771
- ✨(core) create AccountServiceAuthentication backend #771
- ✨(core) create AccountService model #771
- 🧱(helm) disable createsuperuser job by setting #863

View File

@@ -0,0 +1,16 @@
"""URLs for plugins"""
from django.conf import settings
from django.urls import include, path
plugins_urlpatterns = []
# Try to import and include URLs from each installed plugin
for app in settings.INSTALLED_PLUGINS:
try:
plugins_urlpatterns.append(path("", include(f"{app}.urls")))
except (ImportError, AttributeError):
# Skip if app doesn't have urls.py
continue
urlpatterns = plugins_urlpatterns

View File

@@ -13,12 +13,15 @@ from drf_spectacular.views import (
)
from oauth2_provider import urls as oauth2_urls
from core.plugins import urls as plugin_urls
from debug import urls as debug_urls
from . import api_urls, resource_server_urls
API_VERSION = settings.API_VERSION
urlpatterns = (
[
path("admin/", admin.site.urls),
@@ -26,6 +29,7 @@ urlpatterns = (
]
+ api_urls.urlpatterns
+ resource_server_urls.urlpatterns
+ plugin_urls.urlpatterns
)
if settings.DEBUG:

View File

@@ -0,0 +1 @@
"""API for La Suite plugin"""

View File

@@ -0,0 +1,56 @@
"""API viewsets for La Suite plugin"""
from functools import reduce
from operator import iconcat
from rest_framework import viewsets
from rest_framework.mixins import ListModelMixin
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
from core.authentication.backends import AccountServiceAuthentication
from core.models import Organization
class ScopeAPIPermission(BasePermission):
"""Permission to check if the user has the correct scope."""
def has_permission(self, request, view):
"""Check if the user has the correct scope."""
if not request.auth:
return False
return view.scope in request.user.scopes
class ActiveOrganizationsSiret(viewsets.GenericViewSet, ListModelMixin):
"""
ViewSet to list all SIRET of active communes.
* Requires API key authentication.
* Only services with the correct scope are able to access this view.
"""
authentication_classes = [AccountServiceAuthentication]
permission_classes = [ScopeAPIPermission]
scope = "la-suite-list-organizations-siret"
def get_queryset(self):
"""
Return queryset of active communes.
"""
return Organization.objects.filter(
metadata__is_commune=True,
registration_id_list__isnull=False,
is_active=True,
).order_by("-created_at")
def list(self, request, *args, **kwargs):
"""
Return a list of all SIRET of active communes.
"""
registration_ids_lists = self.get_queryset().values_list(
"registration_id_list", flat=True
)
registration_ids = reduce(iconcat, registration_ids_lists, [])
return Response(registration_ids)

View File

@@ -0,0 +1 @@
"""Test for the La Suite plugin API"""

View File

@@ -0,0 +1,81 @@
"""Test for the La Suite plugin API active organizations siret"""
from importlib import import_module, reload
from django.test import override_settings
from django.urls import clear_url_caches, set_urlconf
import pytest
from rest_framework import status
from rest_framework.test import APIClient
from core import factories
pytestmark = pytest.mark.django_db
API_URL = "/la-suite/v1.0/siret/"
@pytest.fixture(name="plugin_urls")
def reload_urlconf(settings):
"""Reload the urlconf before"""
settings.INSTALLED_PLUGINS = ["plugins.la_suite"]
reload(import_module("core.plugins.urls"))
reload(import_module(settings.ROOT_URLCONF))
clear_url_caches()
set_urlconf(None)
yield
settings.INSTALLED_PLUGINS = []
reload(import_module("core.plugins.urls"))
reload(import_module(settings.ROOT_URLCONF))
clear_url_caches()
set_urlconf(None)
# pylint: disable=unused-argument
def test_active_organizations_siret_unauthorized(plugin_urls):
"""Test the active organizations siret API unauthorized"""
client = APIClient()
response = client.get(API_URL)
assert response.status_code == status.HTTP_401_UNAUTHORIZED
# pylint: disable=unused-argument
@override_settings(ACCOUNT_SERVICE_SCOPES=["la-suite-list-organizations-siret"])
def test_active_organizations_siret_authorized(plugin_urls):
"""Test the active organizations siret API authorized"""
account_service = factories.AccountServiceFactory(
name="my_account_service",
api_key="my_api_key",
scopes=["la-suite-list-organizations-siret"],
)
factories.OrganizationFactory(
metadata={"is_public_service": True, "is_commune": True},
registration_id_list=["11111111111111", "22222222222222"],
is_active=True,
)
factories.OrganizationFactory(
metadata={"is_public_service": True, "is_commune": False},
registration_id_list=["33333333333333"],
is_active=True,
)
factories.OrganizationFactory(
metadata={"is_public_service": True, "is_commune": True},
registration_id_list=["44444444444444"],
is_active=False,
)
factories.OrganizationFactory(
metadata={"is_public_service": True, "is_commune": False},
registration_id_list=["55555555555555"],
is_active=True,
)
client = APIClient()
client.credentials(HTTP_AUTHORIZATION=f"ApiKey {account_service.api_key}")
response = client.get(API_URL)
assert response.status_code == status.HTTP_200_OK
assert response.data == ["11111111111111", "22222222222222"]

View File

@@ -0,0 +1,14 @@
"""API URL Configuration for La Suite plugin"""
from rest_framework.routers import DefaultRouter
from .api.viewsets import ActiveOrganizationsSiret
router = DefaultRouter()
router.register(
"la-suite/v1.0/siret",
ActiveOrganizationsSiret,
basename="active-organization-sirets",
)
urlpatterns = router.urls