diff --git a/Makefile b/Makefile index adf44606f..8c457c1a6 100644 --- a/Makefile +++ b/Makefile @@ -20,3 +20,7 @@ messagesde: requirements: pyproject.toml uv pip compile -o requirements.txt pyproject.toml -p 3.10 uv pip compile -o requirements-test.txt --extra test pyproject.toml -p 3.10 + +openapi: + python manage.py generateschema --file froide/openapi-schema.yaml + pnpm run openapi diff --git a/froide/conftest.py b/froide/conftest.py index 302546fb0..4fe94f802 100644 --- a/froide/conftest.py +++ b/froide/conftest.py @@ -10,6 +10,7 @@ from froide.foirequest.models import FoiMessage, FoiRequest from froide.foirequest.signals import email_left_queue from froide.foirequest.tests.factories import ( + FoiMessageDraftFactory, FoiMessageFactory, FoiProjectFactory, FoiRequestFactory, @@ -33,6 +34,7 @@ register(FoiRequestFollowerFactory) register(PublicBodyFactory) register(FoiMessageFactory) +register(FoiMessageDraftFactory) register(ClassificationFactory) register(FoiLawFactory) register(JurisdictionFactory) diff --git a/froide/foirequest/admin.py b/froide/foirequest/admin.py index f7e5da6ef..d13175369 100644 --- a/froide/foirequest/admin.py +++ b/froide/foirequest/admin.py @@ -22,6 +22,7 @@ from froide.account.models import UserTag from froide.comments.models import FroideComment +from froide.foirequest.models.message import FoiMessageDraft from froide.guide.models import Action from froide.guide.utils import assign_guidance_action from froide.helper.admin_utils import ( @@ -521,8 +522,7 @@ class MessageTagsFilter(MultiFilterMixin, TaggitListFilter): @admin.register(FoiMessage) class FoiMessageAdmin(admin.ModelAdmin): save_on_top = True - list_display = ( - "is_draft", + list_display = [ "subject", "timestamp", "message_page", @@ -532,7 +532,7 @@ class FoiMessageAdmin(admin.ModelAdmin): "registered_mail_date", "kind", "get_deliverystatus_display", - ) + ] list_filter = ( "kind", "is_response", @@ -752,6 +752,22 @@ def add_comment( ) +@admin.register(FoiMessageDraft) +class FoiMessageDraftAdmin(FoiMessageAdmin): + list_display = ("pk", "request_page", "timestamp", "kind", "user") + + def request_page(self, obj): + return format_html( + '{}', obj.request.get_absolute_short_url(), _("on site") + ) + + def user(self, obj): + return obj.request.user + + def get_queryset(self, request): + return super().get_queryset(request).prefetch_related("deliverystatus") + + @admin.register(MessageTag) class MessageTagAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ("name",)} diff --git a/froide/foirequest/api_views.py b/froide/foirequest/api_views.py deleted file mode 100644 index 7f495852a..000000000 --- a/froide/foirequest/api_views.py +++ /dev/null @@ -1,686 +0,0 @@ -from django.contrib.auth import get_user_model -from django.db.models import Prefetch, Q - -from django_filters import rest_framework as filters -from oauth2_provider.contrib.rest_framework import TokenHasScope -from rest_framework import mixins, serializers, status, throttling, viewsets -from rest_framework.decorators import action -from rest_framework.response import Response -from taggit.models import Tag - -from froide.campaign.models import Campaign -from froide.document.api_views import DocumentSerializer -from froide.foirequest.forms.message import TransferUploadForm -from froide.foirequest.models.message import MessageKind -from froide.helper.auth import get_write_queryset -from froide.helper.search.api_views import ESQueryMixin -from froide.helper.text_diff import get_differences -from froide.publicbody.api_views import ( - FoiLawSerializer, - PublicBodySerializer, - SimplePublicBodySerializer, -) -from froide.publicbody.models import PublicBody - -from .auth import ( - can_read_foirequest_authenticated, - get_read_foiattachment_queryset, - get_read_foimessage_queryset, - get_read_foirequest_queryset, -) -from .documents import FoiRequestDocument -from .filters import FoiRequestFilterSet -from .models import FoiAttachment, FoiMessage, FoiRequest -from .services import CreateRequestService -from .utils import check_throttle -from .validators import clean_reference - -User = get_user_model() - - -def filter_by_user_queryset(request): - user_filter = Q(is_active=True, private=False) - if request is None or not request.user.is_authenticated: - return User.objects.filter(user_filter) - - user = request.user - token = request.auth - - if not token and user.is_superuser: - return User.objects.all() - - # Either not OAuth or OAuth and valid token - if not token or token.is_valid(["read:request"]): - # allow filter by own user - user_filter |= Q(pk=request.user.pk) - - return User.objects.filter(user_filter) - - -def filter_by_authenticated_user_queryset(request): - if request is None or not request.user.is_authenticated: - return User.objects.none() - - user = request.user - token = request.auth - - if not token and user.is_superuser: - # Allow superusers complete access - return User.objects.all() - - if not token or token.is_valid(["read:request"]): - # allow filter by own user - return User.objects.filter(id=user.id) - return User.objects.none() - - -class CreateOnlyWithScopePermission(TokenHasScope): - def has_permission(self, request, view): - if view.action not in ("create", "update"): - return True - if not request.user.is_authenticated: - return False - return super().has_permission(request, view) - - -class FoiAttachmentSerializer(serializers.HyperlinkedModelSerializer): - resource_uri = serializers.HyperlinkedIdentityField( - view_name="api:attachment-detail", lookup_field="pk" - ) - converted = serializers.HyperlinkedRelatedField( - view_name="api:attachment-detail", - lookup_field="pk", - read_only=True, - ) - redacted = serializers.HyperlinkedRelatedField( - view_name="api:attachment-detail", - lookup_field="pk", - read_only=True, - ) - belongs_to = serializers.HyperlinkedRelatedField( - read_only=True, view_name="api:message-detail" - ) - document = DocumentSerializer() - site_url = serializers.CharField(source="get_absolute_domain_url", read_only=True) - anchor_url = serializers.CharField(source="get_domain_anchor_url", read_only=True) - file_url = serializers.SerializerMethodField(source="get_file_url", read_only=True) - - class Meta: - model = FoiAttachment - depth = 0 - fields = ( - "resource_uri", - "id", - "belongs_to", - "name", - "filetype", - "size", - "site_url", - "anchor_url", - "file_url", - "pending", - "is_converted", - "converted", - "approved", - "can_approve", - "redacted", - "is_redacted", - "can_redact", - "can_delete", - "is_pdf", - "is_image", - "is_irrelevant", - "document", - ) - - def get_file_url(self, obj): - return obj.get_absolute_domain_file_url(authorized=True) - - -class FoiAttachmentTusSerializer(serializers.Serializer): - message = serializers.IntegerField() - upload = serializers.CharField() - - def validate_message(self, value): - writable_requests = get_write_queryset( - FoiRequest.objects.all(), - self.context["request"], - has_team=True, - scope="upload:message", - ) - try: - return FoiMessage.objects.get( - pk=value, - request__in=writable_requests, - kind=MessageKind.POST, - ) - except FoiMessage.DoesNotExist as e: - raise serializers.ValidationError("Message not found") from e - - def validate(self, data): - self.form = TransferUploadForm( - data=data, foimessage=data["message"], user=self.context["request"].user - ) - if not self.form.is_valid(): - raise serializers.ValidationError("Invalid upload") - - return data - - def create(self, validated_data): - added = self.form.save(self.context["request"]) - return added[0] - - -class FoiAttachmentFilter(filters.FilterSet): - class Meta: - model = FoiAttachment - fields = ( - "name", - "filetype", - "approved", - "is_redacted", - "belongs_to", - ) - - -class FoiAttachmentViewSet( - mixins.CreateModelMixin, - mixins.ListModelMixin, - mixins.RetrieveModelMixin, - viewsets.GenericViewSet, -): - serializer_action_classes = { - "create": FoiAttachmentTusSerializer, - "list": FoiAttachmentSerializer, - "retrieve": FoiAttachmentSerializer, - } - filter_backends = (filters.DjangoFilterBackend,) - filterset_class = FoiAttachmentFilter - permission_classes = (CreateOnlyWithScopePermission,) - required_scopes = ["upload:message"] - - def get_serializer_class(self): - try: - return self.serializer_action_classes[self.action] - except (KeyError, AttributeError): - return FoiRequestListSerializer - - def get_queryset(self): - qs = get_read_foiattachment_queryset(self.request) - return self.optimize_query(qs) - - def optimize_query(self, qs): - return qs.prefetch_related( - "belongs_to", - "belongs_to__request", - "belongs_to__request__user", - ) - - def create(self, request, *args, **kwargs): - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - instance = self.perform_create(serializer) - data = FoiAttachmentSerializer(instance, context={"request": request}).data - return Response(data, status=status.HTTP_201_CREATED) - - def perform_create(self, serializer): - return serializer.save() - - -class FoiMessageSerializer(serializers.HyperlinkedModelSerializer): - resource_uri = serializers.HyperlinkedIdentityField( - view_name="api:message-detail", lookup_field="pk" - ) - request = serializers.HyperlinkedRelatedField( - read_only=True, view_name="api:request-detail" - ) - attachments = serializers.SerializerMethodField(source="get_attachments") - sender_public_body = serializers.HyperlinkedRelatedField( - read_only=True, view_name="api:publicbody-detail" - ) - recipient_public_body = serializers.HyperlinkedRelatedField( - read_only=True, view_name="api:publicbody-detail" - ) - - subject = serializers.SerializerMethodField(source="get_subject") - content = serializers.SerializerMethodField(source="get_content") - redacted_subject = serializers.SerializerMethodField(source="get_redacted_subject") - redacted_content = serializers.SerializerMethodField(source="get_redacted_content") - sender = serializers.CharField() - url = serializers.CharField(source="get_absolute_domain_url") - status_name = serializers.CharField(source="get_status_display") - - class Meta: - model = FoiMessage - depth = 0 - fields = ( - "resource_uri", - "id", - "url", - "request", - "sent", - "is_response", - "is_postal", - "is_draft", - "kind", - "is_escalation", - "content_hidden", - "sender_public_body", - "recipient_public_body", - "status", - "timestamp", - "redacted", - "not_publishable", - "attachments", - "subject", - "content", - "redacted_subject", - "redacted_content", - "sender", - "status_name", - "last_modified_at", - ) - - def _is_authenticated_read(self, obj): - request = self.context["request"] - return can_read_foirequest_authenticated(obj.request, request, allow_code=False) - - def get_subject(self, obj): - if obj.content_hidden and not self._is_authenticated_read(obj): - return "" - return obj.get_subject() - - def get_content(self, obj): - if obj.content_hidden and not self._is_authenticated_read(obj): - return "" - return obj.get_content() - - def get_redacted_subject(self, obj): - if self._is_authenticated_read(obj): - show, hide = obj.subject, obj.subject_redacted - else: - if obj.content_hidden: - return [] - show, hide = obj.subject_redacted, obj.subject - return list(get_differences(show, hide)) - - def get_redacted_content(self, obj): - authenticated_read = self._is_authenticated_read(obj) - if obj.content_hidden and not authenticated_read: - return [] - return obj.get_redacted_content(authenticated_read) - - def get_attachments(self, obj): - if not hasattr(obj, "visible_attachments"): - obj.visible_attachments = get_read_foiattachment_queryset( - self.context["request"], - queryset=FoiAttachment.objects.filter(belongs_to=obj), - ).prefetch_related("belongs_to", "document", "converted", "redacted") - - serializer = FoiAttachmentSerializer( - obj.visible_attachments, # already filtered by prefetch - many=True, - context={"request": self.context["request"]}, - ) - return serializer.data - - -class FoiMessageFilter(filters.FilterSet): - class Meta: - model = FoiMessage - fields = ( - "request", - "kind", - "is_response", - ) - - -class FoiMessageViewSet(viewsets.ReadOnlyModelViewSet): - serializer_class = FoiMessageSerializer - filter_backends = (filters.DjangoFilterBackend,) - filterset_class = FoiMessageFilter - - def get_queryset(self): - qs = get_read_foimessage_queryset(self.request).order_by() - return self.optimize_query(qs) - - def optimize_query(self, qs): - return optimize_message_queryset(self.request, qs) - - -def optimize_message_queryset(request, qs): - atts = get_read_foiattachment_queryset( - request, queryset=FoiAttachment.objects.filter(belongs_to__in=qs) - ).prefetch_related("belongs_to", "document", "converted", "redacted") - return qs.prefetch_related( - "request", - "request__user", - "sender_user", - "sender_public_body", - Prefetch("foiattachment_set", queryset=atts, to_attr="visible_attachments"), - ) - - -class TagListField(serializers.CharField): - child = serializers.CharField() - - def to_representation(self, data): - return [t.name for t in data.all()] - - -class FoiRequestListSerializer(serializers.HyperlinkedModelSerializer): - resource_uri = serializers.HyperlinkedIdentityField( - view_name="api:request-detail", lookup_field="pk" - ) - public_body = SimplePublicBodySerializer(read_only=True) - law = serializers.HyperlinkedRelatedField( - read_only=True, view_name="api:law-detail", lookup_field="pk" - ) - jurisdiction = serializers.HyperlinkedRelatedField( - view_name="api:jurisdiction-detail", lookup_field="pk", read_only=True - ) - same_as = serializers.HyperlinkedRelatedField( - view_name="api:request-detail", lookup_field="pk", read_only=True - ) - user = serializers.SerializerMethodField(source="get_user") - project = serializers.PrimaryKeyRelatedField( - read_only=True, - ) - campaign = serializers.HyperlinkedRelatedField( - read_only=True, view_name="api:campaign-detail", lookup_field="pk" - ) - tags = TagListField() - - description = serializers.CharField(source="get_description") - redacted_description = serializers.SerializerMethodField() - costs = serializers.SerializerMethodField() - - class Meta: - model = FoiRequest - depth = 0 - fields = ( - "resource_uri", - "id", - "url", - "jurisdiction", - "is_foi", - "checked", - "refusal_reason", - "costs", - "public", - "law", - "description", - "redacted_description", - "summary", - "same_as_count", - "same_as", - "due_date", - "resolved_on", - "last_message", - "created_at", - "last_modified_at", - "status", - "public_body", - "resolution", - "slug", - "title", - "reference", - "user", - "project", - "campaign", - "tags", - ) - - def get_user(self, obj): - if obj.user is None: - return None - user = self.context["request"].user - if obj.user == user or user.is_superuser: - return obj.user.pk - if obj.user.private: - return None - return obj.user.pk - - def get_redacted_description(self, obj): - request = self.context["request"] - authenticated_read = can_read_foirequest_authenticated( - obj, request, allow_code=False - ) - return obj.get_redacted_description(authenticated_read) - - def get_costs(self, obj): - return float(obj.costs) - - -class FoiRequestDetailSerializer(FoiRequestListSerializer): - public_body = PublicBodySerializer(read_only=True) - law = FoiLawSerializer(read_only=True) - messages = serializers.SerializerMethodField() - - class Meta(FoiRequestListSerializer.Meta): - fields = FoiRequestListSerializer.Meta.fields + ("messages",) - - def get_messages(self, obj): - qs = optimize_message_queryset( - self.context["request"], FoiMessage.objects.filter(request=obj) - ) - return FoiMessageSerializer( - qs, read_only=True, many=True, context=self.context - ).data - - -class MakeRequestSerializer(serializers.Serializer): - publicbodies = serializers.PrimaryKeyRelatedField( - queryset=PublicBody.objects.all(), many=True - ) - - subject = serializers.CharField(max_length=230) - body = serializers.CharField() - - full_text = serializers.BooleanField(required=False, default=False) - public = serializers.BooleanField(required=False, default=True) - reference = serializers.CharField(required=False, default="") - tags = serializers.ListField( - required=False, child=serializers.CharField(max_length=255) - ) - - def validate_reference(self, value): - cleaned_reference = clean_reference(value) - if value and cleaned_reference != value: - raise serializers.ValidationError("Reference not clean") - return cleaned_reference - - def create(self, validated_data): - service = CreateRequestService(validated_data) - return service.execute(validated_data["request"]) - - -class FoiRequestFilter(filters.FilterSet): - user = filters.ModelChoiceFilter(queryset=filter_by_user_queryset) - tags = filters.CharFilter(method="tag_filter") - categories = filters.CharFilter(method="categories_filter") - classification = filters.CharFilter(method="classification_filter") - reference = filters.CharFilter(method="reference_filter") - follower = filters.ModelChoiceFilter( - queryset=filter_by_authenticated_user_queryset, method="follower_filter" - ) - costs = filters.RangeFilter() - campaign = filters.ModelChoiceFilter( - queryset=Campaign.objects.filter(public=True), - null_value="-", - null_label="No Campaign", - lookup_expr="isnull", - method="campaign_filter", - ) - created_at_after = filters.DateFilter(field_name="created_at", lookup_expr="gte") - created_at_before = filters.DateFilter(field_name="created_at", lookup_expr="lt") - has_same = filters.BooleanFilter( - field_name="same_as", lookup_expr="isnull", exclude=True - ) - - # FIXME: default ordering should be undetermined? - # ordering = filters.OrderingFilter( - # fields=( - # ('last_message', 'last_message'), - # ('first_message', 'first_message') - # ), - # field_labels={ - # '-last_message': 'By last message (latest first)', - # '-first_message': 'By first message (latest first)', - # 'last_message': 'By last message (oldest first)', - # 'first_message': 'By first message (oldest first)', - # } - # ) - - class Meta: - model = FoiRequest - fields = ( - "user", - "is_foi", - "checked", - "jurisdiction", - "tags", - "resolution", - "status", - "reference", - "classification", - "public_body", - "slug", - "costs", - "project", - "campaign", - "law", - ) - - def tag_filter(self, queryset, name, value): - return queryset.filter( - **{ - "tags__name": value, - } - ) - - def categories_filter(self, queryset, name, value): - return queryset.filter( - **{ - "public_body__categories__name": value, - } - ) - - def classification_filter(self, queryset, name, value): - return queryset.filter( - **{ - "public_body__classification__name": value, - } - ) - - def reference_filter(self, queryset, name, value): - return queryset.filter( - **{ - "reference__startswith": value, - } - ) - - def follower_filter(self, queryset, name, value): - return queryset.filter(followers__user=value) - - def campaign_filter(self, queryset, name, value): - if value == "-": - return queryset.filter(campaign__isnull=True) - return queryset.filter(campaign=value) - - -class MakeRequestThrottle(throttling.BaseThrottle): - def allow_request(self, request, view): - return not bool(check_throttle(request.user, FoiRequest)) - - -def throttle_action(throttle_classes): - def inner(method): - def _inner(self, request, *args, **kwargs): - for throttle_class in throttle_classes: - throttle = throttle_class() - if not throttle.allow_request(request, self): - self.throttled(request, throttle.wait()) - return method(self, request, *args, **kwargs) - - return _inner - - return inner - - -class FoiRequestViewSet( - mixins.CreateModelMixin, - mixins.ListModelMixin, - mixins.RetrieveModelMixin, - ESQueryMixin, - viewsets.GenericViewSet, -): - serializer_action_classes = { - "create": MakeRequestSerializer, - "list": FoiRequestListSerializer, - "retrieve": FoiRequestDetailSerializer, - } - filter_backends = (filters.DjangoFilterBackend,) - filterset_class = FoiRequestFilter - permission_classes = (CreateOnlyWithScopePermission,) - required_scopes = ["make:request"] - search_model = FoiRequest - search_document = FoiRequestDocument - read_token_scopes = ["read:request"] - searchfilterset_class = FoiRequestFilterSet - - def get_serializer_class(self): - try: - return self.serializer_action_classes[self.action] - except (KeyError, AttributeError): - return FoiRequestListSerializer - - def get_queryset(self): - qs = get_read_foirequest_queryset(self.request) - return self.optimize_query(qs) - - def optimize_query(self, qs): - extras = () - if self.action == "retrieve": - extras = ("law",) - qs = qs.prefetch_related( - "public_body", "user", "tags", "public_body__jurisdiction", *extras - ) - return qs - - @action(detail=False, methods=["get"]) - def search(self, request): - return self.search_view(request) - - @action( - detail=False, - methods=["get"], - url_path="tags/autocomplete", - url_name="tags-autocomplete", - ) - def tags_autocomplete(self, request): - query = request.GET.get("q", "") - tags = Tag.objects.none() - if query: - tags = ( - Tag.objects.filter(name__istartswith=query) - .only("name") - .order_by("name") - ) - - page = self.paginate_queryset(tags) - return self.get_paginated_response( - [{"value": t.name, "label": t.name} for t in page] - ) - - @throttle_action((MakeRequestThrottle,)) - def create(self, request, *args, **kwargs): - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - instance = self.perform_create(serializer) - data = {"status": "success", "url": instance.get_absolute_domain_url()} - headers = {"Location": str(instance.get_absolute_url())} - return Response(data, status=status.HTTP_201_CREATED, headers=headers) - - def perform_create(self, serializer): - return serializer.save(user=self.request.user, request=self.request) diff --git a/froide/foirequest/api_views/__init__.py b/froide/foirequest/api_views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/froide/foirequest/api_views/attachment.py b/froide/foirequest/api_views/attachment.py new file mode 100644 index 000000000..3a6da208b --- /dev/null +++ b/froide/foirequest/api_views/attachment.py @@ -0,0 +1,78 @@ +from django.contrib.auth import get_user_model + +from django_filters import rest_framework as filters +from rest_framework import mixins, status, viewsets +from rest_framework.response import Response + +from ..auth import ( + CreateOnlyWithScopePermission, + get_read_foiattachment_queryset, +) +from ..models import FoiAttachment +from ..permissions import WriteFoiRequestPermission +from ..serializers import ( + FoiAttachmentSerializer, + FoiAttachmentTusSerializer, + FoiRequestListSerializer, +) + +User = get_user_model() + + +class FoiAttachmentFilter(filters.FilterSet): + class Meta: + model = FoiAttachment + fields = ( + "name", + "filetype", + "approved", + "is_redacted", + "belongs_to", + ) + + +class FoiAttachmentViewSet( + mixins.CreateModelMixin, + mixins.ListModelMixin, + mixins.RetrieveModelMixin, + viewsets.GenericViewSet, +): + serializer_action_classes = { + "create": FoiAttachmentTusSerializer, + "list": FoiAttachmentSerializer, + "retrieve": FoiAttachmentSerializer, + } + filter_backends = (filters.DjangoFilterBackend,) + filterset_class = FoiAttachmentFilter + permission_classes = [ + CreateOnlyWithScopePermission, + WriteFoiRequestPermission, + ] + required_scopes = ["make:message"] + + def get_serializer_class(self): + try: + return self.serializer_action_classes[self.action] + except (KeyError, AttributeError): + return FoiRequestListSerializer + + def get_queryset(self): + qs = get_read_foiattachment_queryset(self.request) + return self.optimize_query(qs) + + def optimize_query(self, qs): + return qs.prefetch_related( + "belongs_to", + "belongs_to__request", + "belongs_to__request__user", + ) + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + instance = self.perform_create(serializer) + data = FoiAttachmentSerializer(instance, context={"request": request}).data + return Response(data, status=status.HTTP_201_CREATED) + + def perform_create(self, serializer): + return serializer.save() diff --git a/froide/foirequest/api_views/message.py b/froide/foirequest/api_views/message.py new file mode 100644 index 000000000..fe79e3756 --- /dev/null +++ b/froide/foirequest/api_views/message.py @@ -0,0 +1,108 @@ +from django.contrib.auth import get_user_model +from django.utils.translation import gettext_lazy as _ + +from django_filters import rest_framework as filters +from rest_framework import permissions, viewsets +from rest_framework.decorators import action +from rest_framework.response import Response +from rest_framework.viewsets import mixins + +from ..auth import ( + get_read_foimessage_queryset, +) +from ..models import FoiMessage, FoiMessageDraft, FoiRequest +from ..permissions import ( + OnlyEditableWhenDraftPermission, + WriteFoiRequestPermission, +) +from ..serializers import ( + FoiMessageDraftSerializer, + FoiMessageSerializer, + optimize_message_queryset, +) + +User = get_user_model() + + +class FoiMessageFilter(filters.FilterSet): + class Meta: + model = FoiMessage + fields = ("request", "kind", "is_response") + + +class FoiMessageDraftFilter(filters.FilterSet): + class Meta: + model = FoiMessageDraft + fields = ("request",) + + +class FoiMessageViewSet(viewsets.ReadOnlyModelViewSet): + serializer_class = FoiMessageSerializer + filter_backends = (filters.DjangoFilterBackend,) + filterset_class = FoiMessageFilter + + def get_queryset(self): + qs = get_read_foimessage_queryset(self.request).order_by() + return self.optimize_query(qs) + + def optimize_query(self, qs): + return optimize_message_queryset(self.request, qs) + + +class FoiMessageDraftViewSet( + FoiMessageViewSet, + mixins.CreateModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, +): + serializer_class = FoiMessageDraftSerializer + filterset_class = FoiMessageDraftFilter + required_scopes = ["make:message"] + permission_classes = [ + permissions.IsAuthenticatedOrReadOnly, + WriteFoiRequestPermission, + OnlyEditableWhenDraftPermission, + ] + + def get_queryset(self): + qs = get_read_foimessage_queryset( + self.request, queryset=FoiMessageDraft.objects.all() + ).order_by() + return self.optimize_query(qs) + + @action(detail=True, methods=["post"]) + def publish(self, request, pk=None): + message = self.get_object() + message.is_draft = False + + if not message.is_response: + message.sender_user = request.user + + if not message.can_be_published(): + if message.is_response: + error_message = _( + "Response messages must have a sender public body, no sender user and no recipient public body." + ) + else: + error_message = _( + "Non-response messages must have a recipent public body, but no sender public body." + ) + + return Response({"detail": error_message}, status=400) + + message.save() + + if message.is_response: + FoiRequest.message_received.send( + sender=message.request, message=message, user=request.user + ) + else: + FoiRequest.message_sent.send( + sender=message.request, message=message, user=request.user + ) + + # return it as a regular message + serializer = FoiMessageSerializer( + message, context=self.get_serializer_context() + ) + return Response(serializer.data) diff --git a/froide/foirequest/api_views/request.py b/froide/foirequest/api_views/request.py new file mode 100644 index 000000000..d01a4cc80 --- /dev/null +++ b/froide/foirequest/api_views/request.py @@ -0,0 +1,241 @@ +from django.contrib.auth import get_user_model +from django.db.models import Q + +from django_filters import rest_framework as filters +from rest_framework import mixins, status, throttling, viewsets +from rest_framework.decorators import action +from rest_framework.response import Response +from taggit.models import Tag + +from froide.campaign.models import Campaign +from froide.helper.search.api_views import ESQueryMixin + +from ..auth import ( + CreateOnlyWithScopePermission, + get_read_foirequest_queryset, + throttle_action, +) +from ..documents import FoiRequestDocument +from ..filters import FoiRequestFilterSet +from ..models import FoiRequest +from ..serializers import ( + FoiRequestDetailSerializer, + FoiRequestListSerializer, + MakeRequestSerializer, +) +from ..utils import check_throttle + +User = get_user_model() + + +def filter_by_user_queryset(request): + user_filter = Q(is_active=True, private=False) + if request is None or not request.user.is_authenticated: + return User.objects.filter(user_filter) + + user = request.user + token = request.auth + + if not token and user.is_superuser: + return User.objects.all() + + # Either not OAuth or OAuth and valid token + if not token or token.is_valid(["read:request"]): + # allow filter by own user + user_filter |= Q(pk=request.user.pk) + + return User.objects.filter(user_filter) + + +def filter_by_authenticated_user_queryset(request): + if request is None or not request.user.is_authenticated: + return User.objects.none() + + user = request.user + token = request.auth + + if not token and user.is_superuser: + # Allow superusers complete access + return User.objects.all() + + if not token or token.is_valid(["read:request"]): + # allow filter by own user + return User.objects.filter(id=user.id) + return User.objects.none() + + +class FoiRequestFilter(filters.FilterSet): + user = filters.ModelChoiceFilter(queryset=filter_by_user_queryset) + tags = filters.CharFilter(method="tag_filter") + categories = filters.CharFilter(method="categories_filter") + classification = filters.CharFilter(method="classification_filter") + reference = filters.CharFilter(method="reference_filter") + follower = filters.ModelChoiceFilter( + queryset=filter_by_authenticated_user_queryset, method="follower_filter" + ) + costs = filters.RangeFilter() + campaign = filters.ModelChoiceFilter( + queryset=Campaign.objects.filter(public=True), + null_value="-", + null_label="No Campaign", + lookup_expr="isnull", + method="campaign_filter", + ) + created_at_after = filters.DateFilter(field_name="created_at", lookup_expr="gte") + created_at_before = filters.DateFilter(field_name="created_at", lookup_expr="lt") + has_same = filters.BooleanFilter( + field_name="same_as", lookup_expr="isnull", exclude=True + ) + + # FIXME: default ordering should be undetermined? + # ordering = filters.OrderingFilter( + # fields=( + # ('last_message', 'last_message'), + # ('first_message', 'first_message') + # ), + # field_labels={ + # '-last_message': 'By last message (latest first)', + # '-first_message': 'By first message (latest first)', + # 'last_message': 'By last message (oldest first)', + # 'first_message': 'By first message (oldest first)', + # } + # ) + + class Meta: + model = FoiRequest + fields = ( + "user", + "is_foi", + "checked", + "jurisdiction", + "tags", + "resolution", + "status", + "reference", + "classification", + "public_body", + "slug", + "costs", + "project", + "campaign", + "law", + ) + + def tag_filter(self, queryset, name, value): + return queryset.filter( + **{ + "tags__name": value, + } + ) + + def categories_filter(self, queryset, name, value): + return queryset.filter( + **{ + "public_body__categories__name": value, + } + ) + + def classification_filter(self, queryset, name, value): + return queryset.filter( + **{ + "public_body__classification__name": value, + } + ) + + def reference_filter(self, queryset, name, value): + return queryset.filter( + **{ + "reference__startswith": value, + } + ) + + def follower_filter(self, queryset, name, value): + return queryset.filter(followers__user=value) + + def campaign_filter(self, queryset, name, value): + if value == "-": + return queryset.filter(campaign__isnull=True) + return queryset.filter(campaign=value) + + +class MakeRequestThrottle(throttling.BaseThrottle): + def allow_request(self, request, view): + return not bool(check_throttle(request.user, FoiRequest)) + + +class FoiRequestViewSet( + mixins.CreateModelMixin, + mixins.ListModelMixin, + mixins.RetrieveModelMixin, + ESQueryMixin, + viewsets.GenericViewSet, +): + serializer_action_classes = { + "create": MakeRequestSerializer, + "list": FoiRequestListSerializer, + "retrieve": FoiRequestDetailSerializer, + } + filter_backends = (filters.DjangoFilterBackend,) + filterset_class = FoiRequestFilter + permission_classes = (CreateOnlyWithScopePermission,) + required_scopes = ["make:request"] + search_model = FoiRequest + search_document = FoiRequestDocument + read_token_scopes = ["read:request"] + searchfilterset_class = FoiRequestFilterSet + + def get_serializer_class(self): + try: + return self.serializer_action_classes[self.action] + except (KeyError, AttributeError): + return FoiRequestListSerializer + + def get_queryset(self): + qs = get_read_foirequest_queryset(self.request) + return self.optimize_query(qs) + + def optimize_query(self, qs): + extras = () + if self.action == "retrieve": + extras = ("law",) + qs = qs.prefetch_related( + "public_body", "user", "tags", "public_body__jurisdiction", *extras + ) + return qs + + @action(detail=False, methods=["get"]) + def search(self, request): + return self.search_view(request) + + @action( + detail=False, + methods=["get"], + url_path="tags/autocomplete", + url_name="tags-autocomplete", + ) + def tags_autocomplete(self, request): + query = request.GET.get("q", "") + tags = Tag.objects.none() + if query: + tags = ( + Tag.objects.filter(name__istartswith=query) + .only("name") + .order_by("name") + ) + + page = self.paginate_queryset(tags) + return self.get_paginated_response( + [{"value": t.name, "label": t.name} for t in page] + ) + + @throttle_action((MakeRequestThrottle,)) + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + instance = self.perform_create(serializer) + data = {"status": "success", "url": instance.get_absolute_domain_url()} + headers = {"Location": str(instance.get_absolute_url())} + return Response(data, status=status.HTTP_201_CREATED, headers=headers) + + def perform_create(self, serializer): + return serializer.save(user=self.request.user, request=self.request) diff --git a/froide/foirequest/apps.py b/froide/foirequest/apps.py index c8f95832d..2c2bf39de 100644 --- a/froide/foirequest/apps.py +++ b/froide/foirequest/apps.py @@ -23,11 +23,12 @@ def ready(self): from froide.account.export import registry from froide.api import api_router from froide.foirequest import signals # noqa - from froide.foirequest.api_views import ( - FoiAttachmentViewSet, + from froide.foirequest.api_views.attachment import FoiAttachmentViewSet + from froide.foirequest.api_views.message import ( + FoiMessageDraftViewSet, FoiMessageViewSet, - FoiRequestViewSet, ) + from froide.foirequest.api_views.request import FoiRequestViewSet from froide.helper.search import search_registry from froide.team import team_changed @@ -50,6 +51,9 @@ def ready(self): account_confirmed.connect(send_request_when_account_confirmed) api_router.register(r"request", FoiRequestViewSet, basename="request") + api_router.register( + r"message/draft", FoiMessageDraftViewSet, basename="message-draft" + ) api_router.register(r"message", FoiMessageViewSet, basename="message") api_router.register(r"attachment", FoiAttachmentViewSet, basename="attachment") diff --git a/froide/foirequest/auth.py b/froide/foirequest/auth.py index 805e3c40b..64f406d8b 100644 --- a/froide/foirequest/auth.py +++ b/froide/foirequest/auth.py @@ -9,6 +9,7 @@ from django.utils.translation import override from crossdomainmedia import CrossDomainMediaAuth +from oauth2_provider.contrib.rest_framework import TokenHasScope from froide.helper.auth import ( can_manage_object, @@ -26,7 +27,8 @@ def get_campaign_auth_foirequests_filter(request: HttpRequest, fk_path=None): - if not request.user.is_staff: + # request is not available when called from manage.py generateschema + if not request or not request.user.is_staff: return None # staff user can act on all campaign-requests @@ -156,8 +158,10 @@ def can_read_foiproject_authenticated( @lru_cache() -def can_write_foirequest(foirequest: FoiRequest, request: HttpRequest) -> bool: - if can_write_object(foirequest, request): +def can_write_foirequest( + foirequest: FoiRequest, request: HttpRequest, scope=None +) -> bool: + if can_write_object(foirequest, request, scope): return True if foirequest.project: @@ -345,3 +349,28 @@ def get_media_file_path(self) -> str: """ obj = self.context["object"] return obj.file.name + + +def throttle_action(throttle_classes): + def inner(method): + def _inner(self, request, *args, **kwargs): + for throttle_class in throttle_classes: + throttle = throttle_class() + if not throttle.allow_request(request, self): + self.throttled(request, throttle.wait()) + return method(self, request, *args, **kwargs) + + return _inner + + return inner + + +class CreateOnlyWithScopePermission(TokenHasScope): + def has_permission(self, request, view): + if view.action not in ("create", "update"): + return True + if request.user.is_authenticated and request.auth is None: + # allow api use with session authentication + # see https://www.django-rest-framework.org/api-guide/authentication/#sessionauthentication + return True + return super().has_permission(request, view) diff --git a/froide/foirequest/models/__init__.py b/froide/foirequest/models/__init__.py index bb84511d1..75059411d 100644 --- a/froide/foirequest/models/__init__.py +++ b/froide/foirequest/models/__init__.py @@ -1,7 +1,13 @@ from .attachment import FoiAttachment from .deferred import DeferredMessage from .draft import RequestDraft -from .message import DeliveryStatus, FoiMessage, MessageTag, TaggedMessage +from .message import ( + DeliveryStatus, + FoiMessage, + FoiMessageDraft, + MessageTag, + TaggedMessage, +) from .project import FoiProject from .request import FoiRequest, TaggedFoiRequest from .suggestion import PublicBodySuggestion @@ -12,6 +18,7 @@ "FoiRequest", "TaggedFoiRequest", "FoiMessage", + "FoiMessageDraft", "FoiAttachment", "FoiEvent", "DeferredMessage", diff --git a/froide/foirequest/models/message.py b/froide/foirequest/models/message.py index 69eca030b..16bdf8a27 100644 --- a/froide/foirequest/models/message.py +++ b/froide/foirequest/models/message.py @@ -37,12 +37,20 @@ def get_throttle_filter(self, queryset, user, extra_filters=None): qs = qs.filter(**extra_filters) return qs, "timestamp" - -class FoiMessageNoDraftsManager(FoiMessageManager): def get_queryset(self): return super().get_queryset().filter(is_draft=False) +class FoiMessageDraftManager(FoiMessageManager): + def get_queryset(self): + # need to call models.Manager, since FoiMessageManager removes drafts + return super(models.Manager, self).get_queryset().filter(is_draft=True) + + def create(self, **kwargs): + kwargs.setdefault("is_draft", True) + return super().create(**kwargs) + + class MessageTag(TagBase): class Meta: verbose_name = _("message tag") @@ -64,12 +72,21 @@ class MessageKind(models.TextChoices): EMAIL = ("email", _("email")) POST = ("post", _("postal mail")) FAX = ("fax", _("fax")) + # uploads by public bodies using link in foirequest UPLOAD = ("upload", _("upload")) PHONE = ("phone", _("phone call")) VISIT = ("visit", _("visit in person")) IMPORT = ("import", _("automatically imported")) +# users are allowed to only create messages of these kinds +# the other kinds can only be created by the system +MESSAGE_KIND_USER_ALLOWED = [ + MessageKind.POST, + MessageKind.PHONE, + MessageKind.VISIT, +] + MESSAGE_KIND_ICONS = { MessageKind.EMAIL: "mail", MessageKind.POST: "newspaper-o", @@ -176,7 +193,6 @@ class FoiMessage(models.Model): confirmation_sent = models.BooleanField(_("Confirmation sent?"), default=False) objects = FoiMessageManager() - no_drafts = FoiMessageNoDraftsManager() class Meta: get_latest_by = "timestamp" @@ -201,6 +217,9 @@ def save(self, *args, **kwargs): super().save(*args, **kwargs) + def is_public(self) -> bool: + return not self.is_draft + @property def is_postal(self): return self.kind == MessageKind.POST @@ -737,6 +756,29 @@ def set_cached_rendered_content(self, authenticated_read, content): FoiMessage.objects.filter(id=self.id).update(**update) +class FoiMessageDraft(FoiMessage): + objects = FoiMessageDraftManager() + + class Meta: + proxy = True + verbose_name = _("Freedom of Information Message Draft") + verbose_name_plural = _("Freedom of Information Message Drafts") + + def can_be_published(self) -> bool: + # see constraints of FoiMessage + if self.is_response: + return ( + self.sender_public_body is not None + and self.recipient_public_body is None + and self.sender_user is None + ) + else: + return ( + self.sender_public_body is None + and self.recipient_public_body is not None + ) + + class Delivery(models.TextChoices): STATUS_UNKNOWN = ("unknown", _("unknown")) STATUS_SENDING = ("sending", _("sending")) diff --git a/froide/foirequest/models/request.py b/froide/foirequest/models/request.py index 6b5122adb..f3e4bac19 100644 --- a/froide/foirequest/models/request.py +++ b/froide/foirequest/models/request.py @@ -475,7 +475,7 @@ def ident(self): def get_messages(self, with_tags=False): qs = ( - self.foimessage_set(manager="no_drafts") + self.foimessage_set.filter(is_draft=False) .select_related( "sender_user", "sender_public_body", "recipient_public_body" ) diff --git a/froide/foirequest/permissions.py b/froide/foirequest/permissions.py new file mode 100644 index 000000000..5868cfc9d --- /dev/null +++ b/froide/foirequest/permissions.py @@ -0,0 +1,33 @@ +from rest_framework import permissions +from rest_framework.views import Request + +from froide.foirequest.models.attachment import FoiAttachment +from froide.foirequest.models.message import FoiMessage +from froide.foirequest.models.request import FoiRequest + +from .auth import can_write_foirequest + + +class WriteFoiRequestPermission(permissions.BasePermission): + def get_foirequest(self, obj) -> FoiRequest: + if isinstance(obj, FoiRequest): + return obj + elif isinstance(obj, FoiMessage): + return obj.request + elif isinstance(obj, FoiAttachment): + return obj.belongs_to.request + raise ValueError("Cannot determine request from object") + + def has_object_permission(self, request: Request, view, obj) -> bool: + if request.method in permissions.SAFE_METHODS: + return True + foirequest = self.get_foirequest(obj) + return can_write_foirequest(foirequest, request) + + +class OnlyEditableWhenDraftPermission(permissions.BasePermission): + def has_object_permission(self, request, view, obj): + if request.method in permissions.SAFE_METHODS: + return True + else: + return obj.is_draft diff --git a/froide/foirequest/serializers.py b/froide/foirequest/serializers.py new file mode 100644 index 000000000..b76429e8c --- /dev/null +++ b/froide/foirequest/serializers.py @@ -0,0 +1,406 @@ +from django.db.models import Prefetch +from django.utils import timezone +from django.utils.translation import gettext as _ + +from rest_framework import permissions, serializers +from rest_framework.views import PermissionDenied + +from froide.document.api_views import DocumentSerializer +from froide.foirequest.forms.message import TransferUploadForm +from froide.foirequest.models.message import ( + MESSAGE_KIND_USER_ALLOWED, + FoiMessageDraft, + MessageKind, +) +from froide.helper.text_diff import get_differences +from froide.publicbody.models import PublicBody +from froide.publicbody.serializers import ( + FoiLawSerializer, + PublicBodyRelatedField, + PublicBodySerializer, + SimplePublicBodySerializer, +) + +from .auth import ( + can_moderate_pii_foirequest, + can_read_foirequest_authenticated, + can_write_foirequest, + get_read_foiattachment_queryset, + get_read_foirequest_queryset, + get_write_foirequest_queryset, +) +from .models import FoiAttachment, FoiMessage, FoiRequest +from .services import CreateRequestService +from .validators import clean_reference + + +class TagListField(serializers.CharField): + child = serializers.CharField() + + def to_representation(self, data): + return [t.name for t in data.all()] + + +class FoiRequestListSerializer(serializers.HyperlinkedModelSerializer): + resource_uri = serializers.HyperlinkedIdentityField( + view_name="api:request-detail", lookup_field="pk" + ) + public_body = SimplePublicBodySerializer(read_only=True) + law = serializers.HyperlinkedRelatedField( + read_only=True, view_name="api:law-detail", lookup_field="pk" + ) + jurisdiction = serializers.HyperlinkedRelatedField( + view_name="api:jurisdiction-detail", lookup_field="pk", read_only=True + ) + same_as = serializers.HyperlinkedRelatedField( + view_name="api:request-detail", lookup_field="pk", read_only=True + ) + user = serializers.SerializerMethodField(source="get_user") + project = serializers.PrimaryKeyRelatedField( + read_only=True, + ) + campaign = serializers.HyperlinkedRelatedField( + read_only=True, view_name="api:campaign-detail", lookup_field="pk" + ) + tags = TagListField() + + description = serializers.CharField(source="get_description") + redacted_description = serializers.SerializerMethodField() + costs = serializers.SerializerMethodField() + + class Meta: + model = FoiRequest + depth = 0 + fields = ( + "resource_uri", + "id", + "url", + "jurisdiction", + "is_foi", + "checked", + "refusal_reason", + "costs", + "public", + "law", + "description", + "redacted_description", + "summary", + "same_as_count", + "same_as", + "due_date", + "resolved_on", + "last_message", + "created_at", + "last_modified_at", + "status", + "public_body", + "resolution", + "slug", + "title", + "reference", + "user", + "project", + "campaign", + "tags", + ) + + def get_user(self, obj): + if obj.user is None: + return None + request = self.context["request"] + user = request.user + if obj.user == user or can_moderate_pii_foirequest(obj, request): + return obj.user.pk + if obj.user.private: + return None + return obj.user.pk + + def get_redacted_description(self, obj): + request = self.context["request"] + authenticated_read = can_read_foirequest_authenticated( + obj, request, allow_code=False + ) + return obj.get_redacted_description(authenticated_read) + + def get_costs(self, obj): + return float(obj.costs) + + +class FoiRequestDetailSerializer(FoiRequestListSerializer): + public_body = PublicBodySerializer(read_only=True) + law = FoiLawSerializer(read_only=True) + messages = serializers.SerializerMethodField() + + class Meta(FoiRequestListSerializer.Meta): + fields = FoiRequestListSerializer.Meta.fields + ("messages",) + + def get_messages(self, obj): + qs = optimize_message_queryset( + self.context["request"], FoiMessage.objects.filter(request=obj) + ) + return FoiMessageSerializer( + qs, read_only=True, many=True, context=self.context + ).data + + +class MakeRequestSerializer(serializers.Serializer): + publicbodies = serializers.PrimaryKeyRelatedField( + queryset=PublicBody.objects.all(), many=True + ) + + subject = serializers.CharField(max_length=230) + body = serializers.CharField() + + full_text = serializers.BooleanField(required=False, default=False) + public = serializers.BooleanField(required=False, default=True) + reference = serializers.CharField(required=False, default="") + tags = serializers.ListField( + required=False, child=serializers.CharField(max_length=255) + ) + + def validate_reference(self, value): + cleaned_reference = clean_reference(value) + if value and cleaned_reference != value: + raise serializers.ValidationError("Reference not clean") + return cleaned_reference + + def create(self, validated_data): + service = CreateRequestService(validated_data) + return service.execute(validated_data["request"]) + + +class FoiRequestRelatedField(serializers.HyperlinkedRelatedField): + view_name = "api:request-detail" + + def get_queryset(self): + request = self.context["request"] + if request.method in permissions.SAFE_METHODS: + return get_read_foirequest_queryset(request) + else: + return get_write_foirequest_queryset(request) + + +class FoiMessageRelatedField(serializers.HyperlinkedRelatedField): + view_name = "api:message-detail" + + def get_url(self, obj, view_name, request, format): + # Unsaved objects will not yet have a valid URL. + if hasattr(obj, "pk") and obj.pk in (None, ""): + return None + + lookup_value = getattr(obj, self.lookup_field) + kwargs = {self.lookup_url_kwarg: lookup_value} + + if isinstance(obj, FoiMessageDraft): + view_name = "api:message-draft-detail" + else: + view_name = "api:message-detail" + + return self.reverse(view_name, kwargs=kwargs, request=request, format=format) + + +class FoiMessageSerializer(serializers.HyperlinkedModelSerializer): + resource_uri = serializers.HyperlinkedIdentityField(view_name="api:message-detail") + request = FoiRequestRelatedField() + attachments = serializers.SerializerMethodField(source="get_attachments") + sender_public_body = PublicBodyRelatedField(required=False, allow_null=True) + recipient_public_body = PublicBodyRelatedField(required=False, allow_null=True) + + subject = serializers.SerializerMethodField(source="get_subject") + content = serializers.SerializerMethodField(source="get_content") + redacted_subject = serializers.SerializerMethodField(source="get_redacted_subject") + redacted_content = serializers.SerializerMethodField(source="get_redacted_content") + sender = serializers.CharField(read_only=True) + url = serializers.CharField(source="get_absolute_domain_url", read_only=True) + status = serializers.ChoiceField( + choices=FoiRequest.STATUS.choices, required=False, allow_blank=True + ) + kind = serializers.ChoiceField(choices=MessageKind.choices, default="post") + status_name = serializers.CharField(source="get_status_display", read_only=True) + timestamp = serializers.DateTimeField(default=timezone.now) + + class Meta: + model = FoiMessage + depth = 0 + fields = ( + "resource_uri", + "id", + "url", + "request", + "sent", + "is_response", + "is_postal", + "is_draft", + "kind", + "is_escalation", + "content_hidden", + "sender_public_body", + "recipient_public_body", + "status", + "timestamp", + "redacted", + "not_publishable", + "attachments", + "subject", + "content", + "redacted_subject", + "redacted_content", + "sender", + "status_name", + "last_modified_at", + ) + read_only_fields = ("sent", "is_draft", "not_publishable", "last_modified_at") + + def _is_authenticated_read(self, obj): + request = self.context["request"] + return can_read_foirequest_authenticated(obj.request, request, allow_code=False) + + def get_subject(self, obj): + if obj.content_hidden and not self._is_authenticated_read(obj): + return "" + return obj.get_subject() + + def get_content(self, obj): + if obj.content_hidden and not self._is_authenticated_read(obj): + return "" + return obj.get_content() + + def get_redacted_subject(self, obj): + if self._is_authenticated_read(obj): + show, hide = obj.subject, obj.subject_redacted + else: + if obj.content_hidden: + return [] + show, hide = obj.subject_redacted, obj.subject + return list(get_differences(show, hide)) + + def get_redacted_content(self, obj): + authenticated_read = self._is_authenticated_read(obj) + if obj.content_hidden and not authenticated_read: + return [] + return obj.get_redacted_content(authenticated_read) + + def get_attachments(self, obj): + if not hasattr(obj, "visible_attachments"): + obj.visible_attachments = get_read_foiattachment_queryset( + self.context["request"], + queryset=FoiAttachment.objects.filter(belongs_to=obj), + ).prefetch_related("belongs_to", "document", "converted", "redacted") + + serializer = FoiAttachmentSerializer( + obj.visible_attachments, # already filtered by prefetch + many=True, + context={"request": self.context["request"]}, + ) + return serializer.data + + def validate_kind(self, value): + # forbid users from e.g. creating a fake e-mail message + if value not in MESSAGE_KIND_USER_ALLOWED: + raise serializers.ValidationError( + _("This message kind can not be created via the API.") + ) + return value + + def validate_request(self, value): + if not can_write_foirequest(value, self.context["request"]): + raise PermissionDenied( + _("You do not have permission to add a message to this request.") + ) + return value + + +class FoiMessageDraftSerializer(FoiMessageSerializer): + resource_uri = serializers.HyperlinkedIdentityField( + view_name="api:message-draft-detail" + ) + + class Meta(FoiMessageSerializer.Meta): + model = FoiMessageDraft + + +class FoiAttachmentSerializer(serializers.HyperlinkedModelSerializer): + resource_uri = serializers.HyperlinkedIdentityField( + view_name="api:attachment-detail", lookup_field="pk" + ) + converted = serializers.HyperlinkedRelatedField( + view_name="api:attachment-detail", + lookup_field="pk", + read_only=True, + ) + redacted = serializers.HyperlinkedRelatedField( + view_name="api:attachment-detail", + lookup_field="pk", + read_only=True, + ) + belongs_to = FoiMessageRelatedField(read_only=True) + document = DocumentSerializer() + site_url = serializers.CharField(source="get_absolute_domain_url", read_only=True) + anchor_url = serializers.CharField(source="get_domain_anchor_url", read_only=True) + file_url = serializers.SerializerMethodField(source="get_file_url", read_only=True) + + class Meta: + model = FoiAttachment + depth = 0 + fields = ( + "resource_uri", + "id", + "belongs_to", + "name", + "filetype", + "size", + "site_url", + "anchor_url", + "file_url", + "pending", + "is_converted", + "converted", + "approved", + "can_approve", + "redacted", + "is_redacted", + "can_redact", + "can_delete", + "is_pdf", + "is_image", + "is_irrelevant", + "document", + ) + + def get_file_url(self, obj): + return obj.get_absolute_domain_file_url(authorized=True) + + +class FoiAttachmentTusSerializer(serializers.Serializer): + message = serializers.HyperlinkedRelatedField( + view_name="api:message-detail", + lookup_field="pk", + queryset=FoiMessage.objects.all(), + ) + upload = serializers.CharField() + + def validate(self, data): + self.form = TransferUploadForm( + data=data, foimessage=data["message"], user=self.context["request"].user + ) + if not self.form.is_valid(): + raise serializers.ValidationError(_("Invalid upload")) + + return data + + def create(self, validated_data): + added = self.form.save(self.context["request"]) + return added[0] + + +def optimize_message_queryset(request, qs): + atts = get_read_foiattachment_queryset( + request, queryset=FoiAttachment.objects.filter(belongs_to__in=qs) + ).prefetch_related("belongs_to", "document", "converted", "redacted") + return qs.prefetch_related( + "request", + "request__user", + "sender_user", + "sender_public_body", + Prefetch("foiattachment_set", queryset=atts, to_attr="visible_attachments"), + ) diff --git a/froide/foirequest/tasks.py b/froide/foirequest/tasks.py index 36514f557..74f939a31 100644 --- a/froide/foirequest/tasks.py +++ b/froide/foirequest/tasks.py @@ -442,10 +442,10 @@ def unpack_zipfile_attachment_task(instance_id): @celery_app.task(name="froide.foirequest.tasks.remove_old_drafts", time_limit=10) def remove_old_drafts(): - from .models import FoiMessage + from .models import FoiMessageDraft - FoiMessage.objects.filter( - is_draft=True, last_modified_at__lt=timezone.now() - timedelta(days=30) + FoiMessageDraft.objects.filter( + last_modified_at__lt=timezone.now() - timedelta(days=30) ).delete() diff --git a/froide/foirequest/tests/__init__.py b/froide/foirequest/tests/__init__.py index 2aa859b15..902825e1c 100644 --- a/froide/foirequest/tests/__init__.py +++ b/froide/foirequest/tests/__init__.py @@ -1,5 +1,5 @@ from .test_admin import * # noqa -from .test_api import * # noqa +from .test_api_request import * # noqa from .test_mail import * # noqa from .test_request import * # noqa from .test_web import * # noqa diff --git a/froide/foirequest/tests/factories.py b/froide/foirequest/tests/factories.py index daeddcadf..97cf5995f 100644 --- a/froide/foirequest/tests/factories.py +++ b/froide/foirequest/tests/factories.py @@ -31,6 +31,7 @@ FoiAttachment, FoiEvent, FoiMessage, + FoiMessageDraft, FoiProject, FoiRequest, PublicBodySuggestion, @@ -156,6 +157,11 @@ class Meta: not_publishable = False +class FoiMessageDraftFactory(FoiMessageFactory): + class Meta: + model = FoiMessageDraft + + class FoiAttachmentFactory(DjangoModelFactory): class Meta: model = FoiAttachment diff --git a/froide/foirequest/tests/test_api_message.py b/froide/foirequest/tests/test_api_message.py new file mode 100644 index 000000000..9353f73b6 --- /dev/null +++ b/froide/foirequest/tests/test_api_message.py @@ -0,0 +1,211 @@ +from django.test import Client +from django.urls import reverse + +import pytest + +from froide.foirequest.models.event import FoiEvent +from froide.foirequest.tests import factories + + +@pytest.mark.django_db +def test_message_draft(client: Client, user): + request = factories.FoiRequestFactory.create(user=user) + ok = client.login(email=user.email, password="froide") + assert ok + + # can't create an email + response = client.post( + "/api/v1/message/draft/", + data={ + "request": reverse("api:request-detail", kwargs={"pk": request.pk}), + "kind": "email", + }, + content_type="application/json", + ) + assert response.status_code == 400 + + # must use draft endpoint + response = client.post( + "/api/v1/message/", + data={ + "request": reverse("api:request-detail", kwargs={"pk": request.pk}), + "kind": "post", + }, + content_type="application/json", + ) + assert response.status_code == 405 + + # create message draft + response = client.post( + "/api/v1/message/draft/", + data={ + "request": reverse("api:request-detail", kwargs={"pk": request.pk}), + "kind": "post", + }, + content_type="application/json", + ) + assert response.status_code == 201 + assert "/draft/" in response.json()["resource_uri"] + + message_id = response.json()["id"] + resource_uri = reverse("api:message-draft-detail", kwargs={"pk": message_id}) + + response = client.patch( + resource_uri, data={"status": "resolved"}, content_type="application/json" + ) + assert response.status_code == 200 + assert response.json()["status"] == "resolved" + + response = client.delete(resource_uri) + assert response.status_code == 204 + + # create message draft + response = client.post( + "/api/v1/message/draft/", + data={ + "request": reverse("api:request-detail", kwargs={"pk": request.pk}), + "kind": "post", + }, + content_type="application/json", + ) + assert response.status_code == 201 + + message_id = response.json()["id"] + resource_uri = reverse("api:message-draft-detail", kwargs={"pk": message_id}) + + # can't set sent stauts + assert response.json()["sent"] is True + response = client.patch( + resource_uri, data={"sent": False}, content_type="application/json" + ) + assert response.json()["sent"] is True + + # doesn't appear in regular messages + response = client.get(reverse("api:message-detail", kwargs={"pk": message_id})) + assert response.status_code == 404 + + # can't publish without recipient + publish_uri = reverse("api:message-draft-publish", kwargs={"pk": message_id}) + response = client.post(publish_uri) + assert response.status_code == 400 + + # letter was sent by public body to user + public_body = factories.PublicBodyFactory.create() + response = client.patch( + resource_uri, + data={ + "sender_public_body": reverse( + "api:publicbody-detail", kwargs={"pk": public_body.pk} + ), + "recipient_public_body": None, + "is_response": True, + }, + content_type="application/json", + ) + assert response.status_code == 200 + + # publish + response = client.post(publish_uri) + assert response.status_code == 200 + assert "/draft/" not in response.json()["resource_uri"] + + # ensure event was created + assert FoiEvent.objects.get( + message=response.json()["id"], event_name="message_received", user=user + ) + + # can't delete anymore + resource_uri = reverse("api:message-detail", kwargs={"pk": message_id}) + response = client.delete(resource_uri) + assert response.status_code == 405 + + resource_uri = reverse("api:message-draft-detail", kwargs={"pk": message_id}) + response = client.delete(resource_uri) + assert response.status_code == 404 + + # user send a message to public body + response = client.post( + "/api/v1/message/draft/", + data={ + "request": reverse("api:request-detail", kwargs={"pk": request.pk}), + "kind": "post", + "recipient_public_body": reverse( + "api:publicbody-detail", kwargs={"pk": public_body.pk} + ), + "sender_public_body": None, + "is_response": False, + }, + content_type="application/json", + ) + assert response.status_code == 201 + print(response.json()) + + message_id = response.json()["id"] + publish_uri = reverse("api:message-draft-publish", kwargs={"pk": message_id}) + + response = client.post(publish_uri) + assert response.status_code == 200 + + # ensure event was created + assert FoiEvent.objects.get( + message=message_id, event_name="message_sent", user=user + ) + + +@pytest.mark.django_db +def test_auth(client, user): + user2 = factories.UserFactory.create() + request = factories.FoiRequestFactory.create(user=user2) + + # need to be logged in + client.logout() + response = client.post( + "/api/v1/message/draft/", + data={ + "request": reverse("api:request-detail", kwargs={"pk": request.pk}), + "kind": "post", + }, + content_type="application/json", + ) + assert response.status_code == 401 + + # can't publish drafts + draft = factories.FoiMessageDraftFactory.create(request=request) + response = client.post( + reverse("api:message-draft-publish", kwargs={"pk": draft.pk}) + ) + assert response.status_code == 401 + + # needs to be own request + client.login(email=user.email, password="froide") + response = client.post( + "/api/v1/message/draft/", + data={ + "request": reverse("api:request-detail", kwargs={"pk": request.pk}), + "kind": "post", + }, + content_type="application/json", + ) + assert response.status_code == 400 + + # create message draft + request2 = factories.FoiRequestFactory.create(user=user) + response = client.post( + "/api/v1/message/draft/", + data={ + "request": reverse("api:request-detail", kwargs={"pk": request2.pk}), + "kind": "post", + }, + content_type="application/json", + ) + assert response.status_code == 201 + + # can't change it to other's people request + response = client.patch( + response.json()["resource_uri"], + data={ + "request": reverse("api:request-detail", kwargs={"pk": request.pk}), + }, + content_type="application/json", + ) + assert response.status_code == 400 diff --git a/froide/foirequest/tests/test_api.py b/froide/foirequest/tests/test_api_request.py similarity index 97% rename from froide/foirequest/tests/test_api.py rename to froide/foirequest/tests/test_api_request.py index 111628d6f..1e1656d88 100644 --- a/froide/foirequest/tests/test_api.py +++ b/froide/foirequest/tests/test_api_request.py @@ -15,8 +15,8 @@ import pytest from oauth2_provider.models import get_access_token_model, get_application_model -from froide.foirequest.api_views import FoiMessageSerializer from froide.foirequest.models import FoiAttachment, FoiRequest +from froide.foirequest.serializers import FoiMessageSerializer from froide.foirequest.tests import factories from froide.publicbody.models import PublicBody from froide.upload.models import Upload @@ -29,6 +29,7 @@ class ApiTest(TestCase): def setUp(self): self.site = factories.make_world() + self.test_user = User.objects.get(username="dummy") def test_list(self): response = self.client.get("/api/v1/request/") @@ -219,6 +220,7 @@ def test_list_private_requests_when_logged_in(self): self.assertEqual(response.status_code, 200) result = json.loads(response.content.decode("utf-8")) self.assertEqual(result["meta"]["total_count"], 2) + self.client.logout() def test_list_private_requests_without_scope(self): response, result = self.api_get(self.request_list_url) @@ -353,6 +355,7 @@ def test_request_creation_with_scope(self): def test_foiattachment_upload(self): mes = factories.FoiMessageFactory.create(request=self.req, kind="post") + mes_url = reverse("api:message-detail", kwargs={"pk": mes.pk}) att_url = reverse("api:attachment-list") upload = Upload.objects.create( @@ -364,22 +367,22 @@ def test_foiattachment_upload(self): upload_url = reverse("api:upload-detail", kwargs={"guid": str(upload.guid)}) response, result = self.api_post( - att_url, {"message": mes.pk, "upload": upload_url} + att_url, {"message": mes_url, "upload": upload_url} ) assert response.status_code == 403 # Set correct scope - self.access_token.scope = "read:request upload:message" + self.access_token.scope = "read:request make:message" self.access_token.save() fake_upload_url = "y" + upload_url[1:] response, result = self.api_post( - att_url, {"message": mes.pk, "upload": fake_upload_url} + att_url, {"message": mes_url, "upload": fake_upload_url} ) assert response.status_code == 400 response, result = self.api_post( - att_url, {"message": mes.pk, "upload": upload_url} + att_url, {"message": mes_url, "upload": upload_url} ) assert response.status_code == 201 diff --git a/froide/foirequest/utils.py b/froide/foirequest/utils.py index 10b04b7b5..5fa7b15bc 100644 --- a/froide/foirequest/utils.py +++ b/froide/foirequest/utils.py @@ -746,12 +746,12 @@ def tz(x): def export_user_data(user): from froide.helper.api_utils import get_fake_api_context - from .api_views import ( + from .models import FoiAttachment, FoiProject + from .serializers import ( FoiAttachmentSerializer, FoiMessageSerializer, FoiRequestListSerializer, ) - from .models import FoiAttachment, FoiProject ctx = get_fake_api_context() foirequests = user.foirequest_set.all().iterator() diff --git a/froide/foirequest/views/make_request.py b/froide/foirequest/views/make_request.py index dfa4f80ef..df621182e 100644 --- a/froide/foirequest/views/make_request.py +++ b/froide/foirequest/views/make_request.py @@ -21,9 +21,9 @@ from froide.helper.auth import get_read_queryset from froide.helper.utils import update_query_params from froide.proof.forms import ProofMessageForm -from froide.publicbody.api_views import PublicBodyListSerializer from froide.publicbody.forms import MultiplePublicBodyForm, PublicBodyForm from froide.publicbody.models import PublicBody +from froide.publicbody.serializers import PublicBodyListSerializer from froide.publicbody.widgets import get_widget_context from ..forms import RequestForm diff --git a/froide/foirequest/views/message.py b/froide/foirequest/views/message.py index 82954f02d..0c7456eaa 100644 --- a/froide/foirequest/views/message.py +++ b/froide/foirequest/views/message.py @@ -23,7 +23,6 @@ from froide.proof.forms import handle_proof_form from froide.upload.forms import get_uppy_i18n -from ..api_views import FoiAttachmentSerializer, FoiMessageSerializer from ..decorators import ( allow_moderate_foirequest, allow_read_foirequest_authenticated, @@ -48,6 +47,7 @@ from ..models import FoiAttachment, FoiEvent, FoiMessage, FoiRequest from ..models.attachment import IMAGE_FILETYPES, PDF_FILETYPES, POSTAL_CONTENT_TYPES from ..models.message import MessageKind +from ..serializers import FoiAttachmentSerializer, FoiMessageSerializer from ..services import ResendBouncedMessageService from ..tasks import convert_images_to_pdf_task from ..utils import check_throttle diff --git a/froide/foirequestfollower/api_views.py b/froide/foirequestfollower/api_views.py index 32f20b6ed..3fd9c233e 100644 --- a/froide/foirequestfollower/api_views.py +++ b/froide/foirequestfollower/api_views.py @@ -188,11 +188,17 @@ def get_foirequest_queryset(self, requests=None): def get_request_filter(self): if not hasattr(self, "_requests_filter"): - requests = self.request.query_params.get("request", "").split(",") + requests = [] try: - requests = [int(r) for r in requests] + # request is not available when called from manage.py generateschema + if self.request: + requests = self.request.query_params.get("request", "").split(",") + requests = [ + int(r) for r in requests if r + ] # filter out empty strings except ValueError: - requests = [] + pass + self._requests_filter = requests return self._requests_filter diff --git a/froide/foirequestfollower/configuration.py b/froide/foirequestfollower/configuration.py index 4d6848d89..bdd2168c5 100644 --- a/froide/foirequestfollower/configuration.py +++ b/froide/foirequestfollower/configuration.py @@ -34,7 +34,8 @@ class FoiRequestFollowConfiguration(FollowConfiguration): def get_content_object_queryset(self, request): qs = get_read_foirequest_queryset(request) - if request.user.is_authenticated: + # request is not available when called from manage.py generateschema + if request and request.user.is_authenticated: qs = qs.exclude(user=request.user) return qs diff --git a/froide/foirequestfollower/tests.py b/froide/foirequestfollower/tests.py index 134b7d09e..4c361b1fd 100644 --- a/froide/foirequestfollower/tests.py +++ b/froide/foirequestfollower/tests.py @@ -14,7 +14,7 @@ from froide.foirequest.models import FoiRequest from froide.foirequest.models.message import MessageKind from froide.foirequest.tests import factories -from froide.foirequest.tests.test_api import OAuthAPIMixin +from froide.foirequest.tests.test_api_request import OAuthAPIMixin from froide.follow.notifications import run_batch_update from .configuration import FoiRequestFollowConfiguration diff --git a/froide/georegion/api_views.py b/froide/georegion/api_views.py index 972ace7c4..a2046aa2b 100644 --- a/froide/georegion/api_views.py +++ b/froide/georegion/api_views.py @@ -174,11 +174,12 @@ class RECONCILIATION_META: properties_dict = {p["id"]: p for p in properties} def get_serializer_class(self): - if self.request.user.is_superuser: - return GeoRegionDetailSerializer try: + # request is not available when called from manage.py generateschema + if self.request and self.request.user.is_superuser: + return GeoRegionDetailSerializer return self.serializer_action_classes[self.action] - except (KeyError, AttributeError): + except KeyError: return GeoRegionSerializer def _search_reconciliation_results(self, query, filters, limit): diff --git a/froide/helper/auth.py b/froide/helper/auth.py index 54bc63cd3..153286d43 100644 --- a/froide/helper/auth.py +++ b/froide/helper/auth.py @@ -77,8 +77,8 @@ def can_read_object_authenticated(obj, request=None): @lru_cache() -def can_write_object(obj, request): - return has_authenticated_access(obj, request) +def can_write_object(obj, request, scope=None): + return has_authenticated_access(obj, request, scope=scope) @lru_cache() @@ -120,7 +120,6 @@ def get_read_queryset( fk_path=None, user_read_filter=None, ): - user = request.user filters = [] if public_field is not None: if public_q is not None: @@ -133,6 +132,11 @@ def get_read_queryset( else: unauth_qs = qs.none() + # request is not available when called from manage.py generateschema + if not request: + return unauth_qs + user = request.user + if not user.is_authenticated: return unauth_qs @@ -171,10 +175,9 @@ def get_read_queryset( def get_write_queryset( qs, request, has_team=False, user_write_filter=None, scope=None, fk_path=None ): - user = request.user - - if not user.is_authenticated: + if not request or not request.user.is_authenticated: return qs.none() + user = request.user # OAuth token token = getattr(request, "auth", None) diff --git a/froide/openapi-schema.yaml b/froide/openapi-schema.yaml new file mode 100644 index 000000000..109e788a5 --- /dev/null +++ b/froide/openapi-schema.yaml @@ -0,0 +1,6223 @@ +openapi: 3.0.2 +info: + title: '' + version: '' +paths: + /api/v1/user/: + get: + operationId: listProfiles + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + type: array + items: {} + text/csv: + schema: + type: array + items: {} + description: '' + tags: + - api + /api/v1/userpreference/{key}/: + get: + operationId: retrieveUserPreference + description: '' + parameters: + - name: key + in: path + required: true + description: '' + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreference' + text/csv: + schema: + $ref: '#/components/schemas/UserPreference' + description: '' + tags: + - api + post: + operationId: createUserPreference + description: '' + parameters: + - name: key + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreference' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserPreference' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserPreference' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreference' + text/csv: + schema: + $ref: '#/components/schemas/UserPreference' + description: '' + tags: + - api + put: + operationId: updateUserPreference + description: '' + parameters: + - name: key + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreference' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserPreference' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserPreference' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreference' + text/csv: + schema: + $ref: '#/components/schemas/UserPreference' + description: '' + tags: + - api + patch: + operationId: partialUpdateUserPreference + description: '' + parameters: + - name: key + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreference' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserPreference' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserPreference' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreference' + text/csv: + schema: + $ref: '#/components/schemas/UserPreference' + description: '' + tags: + - api + /api/v1/request/: + get: + operationId: listFoiRequestLists + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: user + required: false + in: query + description: user + schema: + type: string + - name: is_foi + required: false + in: query + description: is_foi + schema: + type: string + - name: checked + required: false + in: query + description: checked + schema: + type: string + - name: jurisdiction + required: false + in: query + description: jurisdiction + schema: + type: string + - name: tags + required: false + in: query + description: tags + schema: + type: string + - name: resolution + required: false + in: query + description: resolution + schema: + type: string + enum: + - successful + - partially_successful + - not_held + - refused + - user_withdrew_costs + - user_withdrew + - name: status + required: false + in: query + description: status + schema: + type: string + enum: + - awaiting_user_confirmation + - publicbody_needed + - awaiting_publicbody_confirmation + - awaiting_response + - awaiting_classification + - asleep + - resolved + - name: reference + required: false + in: query + description: reference + schema: + type: string + - name: classification + required: false + in: query + description: classification + schema: + type: string + - name: public_body + required: false + in: query + description: public_body + schema: + type: string + - name: slug + required: false + in: query + description: slug + schema: + type: string + - name: costs + required: false + in: query + description: costs + schema: + type: string + - name: project + required: false + in: query + description: project + schema: + type: string + - name: campaign + required: false + in: query + description: campaign + schema: + type: string + - name: law + required: false + in: query + description: law + schema: + type: string + - name: categories + required: false + in: query + description: categories + schema: + type: string + - name: follower + required: false + in: query + description: follower + schema: + type: string + - name: created_at_after + required: false + in: query + description: created_at_after + schema: + type: string + - name: created_at_before + required: false + in: query + description: created_at_before + schema: + type: string + - name: has_same + required: false + in: query + description: has_same + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiRequestList' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiRequestList' + description: '' + tags: + - api + post: + operationId: createMakeRequest + description: '' + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MakeRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/MakeRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/MakeRequest' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/MakeRequest' + text/csv: + schema: + $ref: '#/components/schemas/MakeRequest' + description: '' + tags: + - api + /api/v1/request/search/: + get: + operationId: searchFoiRequestList + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiRequestList' + text/csv: + schema: + $ref: '#/components/schemas/FoiRequestList' + description: '' + tags: + - api + /api/v1/request/tags/autocomplete/: + get: + operationId: tagsAutocompleteFoiRequestList + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiRequestList' + text/csv: + schema: + $ref: '#/components/schemas/FoiRequestList' + description: '' + tags: + - api + /api/v1/request/{id}/: + get: + operationId: retrieveFoiRequestDetail + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: user + required: false + in: query + description: user + schema: + type: string + - name: is_foi + required: false + in: query + description: is_foi + schema: + type: string + - name: checked + required: false + in: query + description: checked + schema: + type: string + - name: jurisdiction + required: false + in: query + description: jurisdiction + schema: + type: string + - name: tags + required: false + in: query + description: tags + schema: + type: string + - name: resolution + required: false + in: query + description: resolution + schema: + type: string + enum: + - successful + - partially_successful + - not_held + - refused + - user_withdrew_costs + - user_withdrew + - name: status + required: false + in: query + description: status + schema: + type: string + enum: + - awaiting_user_confirmation + - publicbody_needed + - awaiting_publicbody_confirmation + - awaiting_response + - awaiting_classification + - asleep + - resolved + - name: reference + required: false + in: query + description: reference + schema: + type: string + - name: classification + required: false + in: query + description: classification + schema: + type: string + - name: public_body + required: false + in: query + description: public_body + schema: + type: string + - name: slug + required: false + in: query + description: slug + schema: + type: string + - name: costs + required: false + in: query + description: costs + schema: + type: string + - name: project + required: false + in: query + description: project + schema: + type: string + - name: campaign + required: false + in: query + description: campaign + schema: + type: string + - name: law + required: false + in: query + description: law + schema: + type: string + - name: categories + required: false + in: query + description: categories + schema: + type: string + - name: follower + required: false + in: query + description: follower + schema: + type: string + - name: created_at_after + required: false + in: query + description: created_at_after + schema: + type: string + - name: created_at_before + required: false + in: query + description: created_at_before + schema: + type: string + - name: has_same + required: false + in: query + description: has_same + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiRequestDetail' + text/csv: + schema: + $ref: '#/components/schemas/FoiRequestDetail' + description: '' + tags: + - api + /api/v1/message/draft/: + get: + operationId: listFoiMessageDrafts + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: request + required: false + in: query + description: request + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiMessageDraft' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiMessageDraft' + description: '' + tags: + - api + post: + operationId: createFoiMessageDraft + description: '' + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + multipart/form-data: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + text/csv: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + description: '' + tags: + - api + /api/v1/message/draft/{id}/: + get: + operationId: retrieveFoiMessageDraft + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: request + required: false + in: query + description: request + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + text/csv: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + description: '' + tags: + - api + put: + operationId: updateFoiMessageDraft + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: request + required: false + in: query + description: request + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + multipart/form-data: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + text/csv: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + description: '' + tags: + - api + patch: + operationId: partialUpdateFoiMessageDraft + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: request + required: false + in: query + description: request + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + multipart/form-data: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + text/csv: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + description: '' + tags: + - api + delete: + operationId: destroyFoiMessageDraft + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: request + required: false + in: query + description: request + schema: + type: string + responses: + '204': + description: '' + tags: + - api + /api/v1/message/: + get: + operationId: listFoiMessages + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: request + required: false + in: query + description: request + schema: + type: string + - name: kind + required: false + in: query + description: kind + schema: + type: string + enum: + - email + - post + - fax + - upload + - phone + - visit + - import + - name: is_response + required: false + in: query + description: is_response + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiMessage' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiMessage' + description: '' + tags: + - api + /api/v1/message/{id}/: + get: + operationId: retrieveFoiMessage + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: request + required: false + in: query + description: request + schema: + type: string + - name: kind + required: false + in: query + description: kind + schema: + type: string + enum: + - email + - post + - fax + - upload + - phone + - visit + - import + - name: is_response + required: false + in: query + description: is_response + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessage' + text/csv: + schema: + $ref: '#/components/schemas/FoiMessage' + description: '' + tags: + - api + /api/v1/attachment/: + get: + operationId: listFoiAttachments + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: name + required: false + in: query + description: name + schema: + type: string + - name: filetype + required: false + in: query + description: filetype + schema: + type: string + - name: approved + required: false + in: query + description: approved + schema: + type: string + - name: is_redacted + required: false + in: query + description: is_redacted + schema: + type: string + - name: belongs_to + required: false + in: query + description: belongs_to + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiAttachment' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiAttachment' + description: '' + tags: + - api + post: + operationId: createFoiAttachmentTus + description: '' + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FoiAttachmentTus' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/FoiAttachmentTus' + multipart/form-data: + schema: + $ref: '#/components/schemas/FoiAttachmentTus' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiAttachmentTus' + text/csv: + schema: + $ref: '#/components/schemas/FoiAttachmentTus' + description: '' + tags: + - api + /api/v1/attachment/{id}/: + get: + operationId: retrieveFoiAttachment + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: name + required: false + in: query + description: name + schema: + type: string + - name: filetype + required: false + in: query + description: filetype + schema: + type: string + - name: approved + required: false + in: query + description: approved + schema: + type: string + - name: is_redacted + required: false + in: query + description: is_redacted + schema: + type: string + - name: belongs_to + required: false + in: query + description: belongs_to + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiAttachment' + text/csv: + schema: + $ref: '#/components/schemas/FoiAttachment' + description: '' + tags: + - api + /api/v1/following/: + get: + operationId: listFoiRequestFollows + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiRequestFollow' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiRequestFollow' + description: '' + tags: + - api + post: + operationId: createCreateFoiRequestFollow + description: '' + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateFoiRequestFollow' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/CreateFoiRequestFollow' + multipart/form-data: + schema: + $ref: '#/components/schemas/CreateFoiRequestFollow' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/CreateFoiRequestFollow' + text/csv: + schema: + $ref: '#/components/schemas/CreateFoiRequestFollow' + description: '' + tags: + - api + /api/v1/georegion/: + get: + operationId: listGeoRegions + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: name + required: false + in: query + description: name + schema: + type: string + - name: level + required: false + in: query + description: level + schema: + type: string + - name: kind + required: false + in: query + description: kind + schema: + type: string + - name: slug + required: false + in: query + description: slug + schema: + type: string + - name: id + required: false + in: query + description: id + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: ancestor + required: false + in: query + description: ancestor + schema: + type: string + - name: latlng + required: false + in: query + description: latlng + schema: + type: string + - name: region_identifier + required: false + in: query + description: region_identifier + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + /api/v1/georegion/autocomplete/: + get: + operationId: autocompleteGeoRegion + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + /api/v1/georegion/reconciliation/: + get: + operationId: reconciliationGeoRegion + description: This is a OpenRefine Reconciliation API endpoint + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + post: + operationId: reconciliationGeoRegion + description: This is a OpenRefine Reconciliation API endpoint + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/GeoRegion' + multipart/form-data: + schema: + $ref: '#/components/schemas/GeoRegion' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + /api/v1/georegion/reconciliation-flyout/: + get: + operationId: reconciliationFlyoutEntityGeoRegion + description: Implements OpenRefine Flyout Entry Point + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + post: + operationId: reconciliationFlyoutEntityGeoRegion + description: Implements OpenRefine Flyout Entry Point + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/GeoRegion' + multipart/form-data: + schema: + $ref: '#/components/schemas/GeoRegion' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + /api/v1/georegion/reconciliation-propose-properties/: + get: + operationId: reconciliationProposePropertiesGeoRegion + description: Implements OpenRefine Data Extension API + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + post: + operationId: reconciliationProposePropertiesGeoRegion + description: Implements OpenRefine Data Extension API + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/GeoRegion' + multipart/form-data: + schema: + $ref: '#/components/schemas/GeoRegion' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + /api/v1/georegion/reconciliation-suggest-service/: + get: + operationId: reconciliationSuggestServiceGeoRegion + description: Implements OpenRefine Suggest Entry Point + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + post: + operationId: reconciliationSuggestServiceGeoRegion + description: Implements OpenRefine Suggest Entry Point + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/GeoRegion' + multipart/form-data: + schema: + $ref: '#/components/schemas/GeoRegion' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegion' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegion' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegion' + description: '' + tags: + - api + /api/v1/georegion/{id}/: + get: + operationId: retrieveGeoRegion + description: '' + parameters: + - name: id + in: path + required: true + description: A unique integer value identifying this Geo Region. + schema: + type: string + - name: name + required: false + in: query + description: name + schema: + type: string + - name: level + required: false + in: query + description: level + schema: + type: string + - name: kind + required: false + in: query + description: kind + schema: + type: string + - name: slug + required: false + in: query + description: slug + schema: + type: string + - name: id + required: false + in: query + description: id + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: ancestor + required: false + in: query + description: ancestor + schema: + type: string + - name: latlng + required: false + in: query + description: latlng + schema: + type: string + - name: region_identifier + required: false + in: query + description: region_identifier + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/GeoRegionDetail' + text/csv: + schema: + $ref: '#/components/schemas/GeoRegionDetail' + application/javascript: + schema: + $ref: '#/components/schemas/GeoRegionDetail' + description: '' + tags: + - api + /api/v1/publicbody/: + get: + operationId: listPublicBodyLists + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: jurisdiction + required: false + in: query + description: jurisdiction + schema: + type: string + - name: slug + required: false + in: query + description: slug + schema: + type: string + - name: classification_id + required: false + in: query + description: classification_id + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: classification + required: false + in: query + description: classification + schema: + type: string + - name: category + required: false + in: query + description: category + schema: + type: string + - name: regions + required: false + in: query + description: regions + schema: + type: string + - name: lnglat + required: false + in: query + description: lnglat + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + /api/v1/publicbody/autocomplete/: + get: + operationId: autocompletePublicBodyList + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + /api/v1/publicbody/reconciliation/: + get: + operationId: reconciliationPublicBodyList + description: This is a OpenRefine Reconciliation API endpoint + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + post: + operationId: reconciliationPublicBodyList + description: This is a OpenRefine Reconciliation API endpoint + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PublicBodyList' + multipart/form-data: + schema: + $ref: '#/components/schemas/PublicBodyList' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + /api/v1/publicbody/reconciliation-flyout/: + get: + operationId: reconciliationFlyoutEntityPublicBodyList + description: Implements OpenRefine Flyout Entry Point + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + post: + operationId: reconciliationFlyoutEntityPublicBodyList + description: Implements OpenRefine Flyout Entry Point + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PublicBodyList' + multipart/form-data: + schema: + $ref: '#/components/schemas/PublicBodyList' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + /api/v1/publicbody/reconciliation-propose-properties/: + get: + operationId: reconciliationProposePropertiesPublicBodyList + description: Implements OpenRefine Data Extension API + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + post: + operationId: reconciliationProposePropertiesPublicBodyList + description: Implements OpenRefine Data Extension API + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PublicBodyList' + multipart/form-data: + schema: + $ref: '#/components/schemas/PublicBodyList' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + /api/v1/publicbody/reconciliation-suggest-service/: + get: + operationId: reconciliationSuggestServicePublicBodyList + description: Implements OpenRefine Suggest Entry Point + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + post: + operationId: reconciliationSuggestServicePublicBodyList + description: Implements OpenRefine Suggest Entry Point + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PublicBodyList' + multipart/form-data: + schema: + $ref: '#/components/schemas/PublicBodyList' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + /api/v1/publicbody/search/: + get: + operationId: searchPublicBodyList + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBodyList' + text/csv: + schema: + $ref: '#/components/schemas/PublicBodyList' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBodyList' + description: '' + tags: + - api + /api/v1/publicbody/{id}/: + get: + operationId: retrievePublicBody + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: jurisdiction + required: false + in: query + description: jurisdiction + schema: + type: string + - name: slug + required: false + in: query + description: slug + schema: + type: string + - name: classification_id + required: false + in: query + description: classification_id + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: classification + required: false + in: query + description: classification + schema: + type: string + - name: category + required: false + in: query + description: category + schema: + type: string + - name: regions + required: false + in: query + description: regions + schema: + type: string + - name: lnglat + required: false + in: query + description: lnglat + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PublicBody' + text/csv: + schema: + $ref: '#/components/schemas/PublicBody' + application/javascript: + schema: + $ref: '#/components/schemas/PublicBody' + description: '' + tags: + - api + /api/v1/category/: + get: + operationId: listCategories + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: name + required: false + in: query + description: name + schema: + type: string + - name: is_topic + required: false + in: query + description: is_topic + schema: + type: string + - name: depth + required: false + in: query + description: depth + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: parent + required: false + in: query + description: parent + schema: + type: string + - name: ancestor + required: false + in: query + description: ancestor + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Category' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Category' + description: '' + tags: + - api + /api/v1/category/autocomplete/: + get: + operationId: autocompleteCategory + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Category' + text/csv: + schema: + $ref: '#/components/schemas/Category' + description: '' + tags: + - api + /api/v1/category/{id}/: + get: + operationId: retrieveCategory + description: '' + parameters: + - name: id + in: path + required: true + description: A unique integer value identifying this category. + schema: + type: string + - name: name + required: false + in: query + description: name + schema: + type: string + - name: is_topic + required: false + in: query + description: is_topic + schema: + type: string + - name: depth + required: false + in: query + description: depth + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: parent + required: false + in: query + description: parent + schema: + type: string + - name: ancestor + required: false + in: query + description: ancestor + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Category' + text/csv: + schema: + $ref: '#/components/schemas/Category' + description: '' + tags: + - api + /api/v1/classification/: + get: + operationId: listClassifications + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: name + required: false + in: query + description: name + schema: + type: string + - name: depth + required: false + in: query + description: depth + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: parent + required: false + in: query + description: parent + schema: + type: string + - name: ancestor + required: false + in: query + description: ancestor + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Classification' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Classification' + description: '' + tags: + - api + /api/v1/classification/{id}/: + get: + operationId: retrieveClassification + description: '' + parameters: + - name: id + in: path + required: true + description: A unique integer value identifying this Classification. + schema: + type: string + - name: name + required: false + in: query + description: name + schema: + type: string + - name: depth + required: false + in: query + description: depth + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: parent + required: false + in: query + description: parent + schema: + type: string + - name: ancestor + required: false + in: query + description: ancestor + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Classification' + text/csv: + schema: + $ref: '#/components/schemas/Classification' + description: '' + tags: + - api + /api/v1/jurisdiction/: + get: + operationId: listJurisdictions + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Jurisdiction' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Jurisdiction' + description: '' + tags: + - api + /api/v1/jurisdiction/{id}/: + get: + operationId: retrieveJurisdiction + description: '' + parameters: + - name: id + in: path + required: true + description: A unique integer value identifying this Jurisdiction. + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Jurisdiction' + text/csv: + schema: + $ref: '#/components/schemas/Jurisdiction' + description: '' + tags: + - api + /api/v1/law/: + get: + operationId: listFoiLaws + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: jurisdiction + required: false + in: query + description: jurisdiction + schema: + type: string + - name: mediator + required: false + in: query + description: mediator + schema: + type: string + - name: id + required: false + in: query + description: id + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: meta + required: false + in: query + description: meta + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiLaw' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/FoiLaw' + description: '' + tags: + - api + /api/v1/law/autocomplete/: + get: + operationId: autocompleteFoiLaw + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiLaw' + text/csv: + schema: + $ref: '#/components/schemas/FoiLaw' + description: '' + tags: + - api + /api/v1/law/{id}/: + get: + operationId: retrieveFoiLaw + description: '' + parameters: + - name: id + in: path + required: true + description: A unique integer value identifying this Freedom of Information + Law. + schema: + type: string + - name: jurisdiction + required: false + in: query + description: jurisdiction + schema: + type: string + - name: mediator + required: false + in: query + description: mediator + schema: + type: string + - name: id + required: false + in: query + description: id + schema: + type: string + - name: q + required: false + in: query + description: q + schema: + type: string + - name: meta + required: false + in: query + description: meta + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiLaw' + text/csv: + schema: + $ref: '#/components/schemas/FoiLaw' + description: '' + tags: + - api + /api/v1/document/: + get: + operationId: listDocuments + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + - name: directory + required: false + in: query + description: directory + schema: + type: string + - name: collection + required: false + in: query + description: collection + schema: + type: string + - name: portal + required: false + in: query + description: portal + schema: + type: string + - name: tag + required: false + in: query + description: tag + schema: + type: string + - name: ids + required: false + in: query + description: ids + schema: + type: string + - name: created_at + required: false + in: query + description: created_at + schema: + type: string + - name: publicbody + required: false + in: query + description: publicbody + schema: + type: string + - name: foirequest + required: false + in: query + description: foirequest + schema: + type: string + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Document' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Document' + description: '' + tags: + - api + /api/v1/document/oembed/: + get: + operationId: oembedDocument + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + text/csv: + schema: + $ref: '#/components/schemas/Document' + description: '' + tags: + - api + /api/v1/document/{id}/: + get: + operationId: retrieveDocumentDetail + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: directory + required: false + in: query + description: directory + schema: + type: string + - name: collection + required: false + in: query + description: collection + schema: + type: string + - name: portal + required: false + in: query + description: portal + schema: + type: string + - name: tag + required: false + in: query + description: tag + schema: + type: string + - name: ids + required: false + in: query + description: ids + schema: + type: string + - name: created_at + required: false + in: query + description: created_at + schema: + type: string + - name: publicbody + required: false + in: query + description: publicbody + schema: + type: string + - name: foirequest + required: false + in: query + description: foirequest + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/DocumentDetail' + text/csv: + schema: + $ref: '#/components/schemas/DocumentDetail' + description: '' + tags: + - api + put: + operationId: updateUpdateDocument + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: directory + required: false + in: query + description: directory + schema: + type: string + - name: collection + required: false + in: query + description: collection + schema: + type: string + - name: portal + required: false + in: query + description: portal + schema: + type: string + - name: tag + required: false + in: query + description: tag + schema: + type: string + - name: ids + required: false + in: query + description: ids + schema: + type: string + - name: created_at + required: false + in: query + description: created_at + schema: + type: string + - name: publicbody + required: false + in: query + description: publicbody + schema: + type: string + - name: foirequest + required: false + in: query + description: foirequest + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateDocument' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UpdateDocument' + multipart/form-data: + schema: + $ref: '#/components/schemas/UpdateDocument' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateDocument' + text/csv: + schema: + $ref: '#/components/schemas/UpdateDocument' + description: '' + tags: + - api + patch: + operationId: partialUpdateDocument + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + - name: directory + required: false + in: query + description: directory + schema: + type: string + - name: collection + required: false + in: query + description: collection + schema: + type: string + - name: portal + required: false + in: query + description: portal + schema: + type: string + - name: tag + required: false + in: query + description: tag + schema: + type: string + - name: ids + required: false + in: query + description: ids + schema: + type: string + - name: created_at + required: false + in: query + description: created_at + schema: + type: string + - name: publicbody + required: false + in: query + description: publicbody + schema: + type: string + - name: foirequest + required: false + in: query + description: foirequest + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Document' + multipart/form-data: + schema: + $ref: '#/components/schemas/Document' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + text/csv: + schema: + $ref: '#/components/schemas/Document' + description: '' + tags: + - api + /api/v1/documentcollection/: + get: + operationId: listDocumentCollections + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/DocumentCollection' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/DocumentCollection' + description: '' + tags: + - api + /api/v1/documentcollection/oembed/: + get: + operationId: oembedDocumentCollection + description: '' + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/DocumentCollection' + text/csv: + schema: + $ref: '#/components/schemas/DocumentCollection' + description: '' + tags: + - api + /api/v1/documentcollection/{id}/: + get: + operationId: retrieveDocumentCollection + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/DocumentCollection' + text/csv: + schema: + $ref: '#/components/schemas/DocumentCollection' + description: '' + tags: + - api + /api/v1/page/: + get: + operationId: listPages + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Page' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Page' + application/xml: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Page' + description: '' + tags: + - api + /api/v1/pageannotation/: + get: + operationId: listPageAnnotations + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/PageAnnotation' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/PageAnnotation' + description: '' + tags: + - api + post: + operationId: createCreatePageAnnotation + description: '' + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreatePageAnnotation' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/CreatePageAnnotation' + multipart/form-data: + schema: + $ref: '#/components/schemas/CreatePageAnnotation' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/CreatePageAnnotation' + text/csv: + schema: + $ref: '#/components/schemas/CreatePageAnnotation' + description: '' + tags: + - api + /api/v1/pageannotation/{id}/: + get: + operationId: retrievePageAnnotation + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PageAnnotation' + text/csv: + schema: + $ref: '#/components/schemas/PageAnnotation' + description: '' + tags: + - api + delete: + operationId: destroyPageAnnotation + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + responses: + '204': + description: '' + tags: + - api + /api/v1/problemreport/: + get: + operationId: listProblemReports + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/ProblemReport' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/ProblemReport' + description: '' + tags: + - api + /api/v1/problemreport/{id}/: + get: + operationId: retrieveProblemReport + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemReport' + text/csv: + schema: + $ref: '#/components/schemas/ProblemReport' + description: '' + tags: + - api + /api/v1/campaign/: + get: + operationId: listCampaigns + description: '' + parameters: + - name: limit + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: offset + required: false + in: query + description: The initial index from which to return the results. + schema: + type: integer + responses: + '200': + content: + application/json: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Campaign' + text/csv: + schema: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=400&limit=100 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?offset=200&limit=100 + results: + type: array + items: + $ref: '#/components/schemas/Campaign' + description: '' + tags: + - api + /api/v1/campaign/{id}/: + get: + operationId: retrieveCampaign + description: '' + parameters: + - name: id + in: path + required: true + description: A unique integer value identifying this campaign. + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Campaign' + text/csv: + schema: + $ref: '#/components/schemas/Campaign' + description: '' + tags: + - api + /api/v1/schema/swagger-ui/: + get: + operationId: listSpectacularSwaggers + description: '' + parameters: [] + responses: + '200': + content: + text/html: + schema: + type: array + items: {} + description: '' + tags: + - api + /api/v1/message/draft/{id}/publish/: + post: + operationId: publishFoiMessageDraft + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + multipart/form-data: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + text/csv: + schema: + $ref: '#/components/schemas/FoiMessageDraft' + description: '' + tags: + - api + /api/v1/problemreport/{id}/claim/: + post: + operationId: claimProblemReport + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemReport' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProblemReport' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProblemReport' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemReport' + text/csv: + schema: + $ref: '#/components/schemas/ProblemReport' + description: '' + tags: + - api + /api/v1/problemreport/{id}/escalate/: + post: + operationId: escalateProblemReport + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemReport' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProblemReport' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProblemReport' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemReport' + text/csv: + schema: + $ref: '#/components/schemas/ProblemReport' + description: '' + tags: + - api + /api/v1/problemreport/{id}/resolve/: + post: + operationId: resolveProblemReport + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemReport' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProblemReport' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProblemReport' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemReport' + text/csv: + schema: + $ref: '#/components/schemas/ProblemReport' + description: '' + tags: + - api + /api/v1/problemreport/{id}/unclaim/: + post: + operationId: unclaimProblemReport + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemReport' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ProblemReport' + multipart/form-data: + schema: + $ref: '#/components/schemas/ProblemReport' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemReport' + text/csv: + schema: + $ref: '#/components/schemas/ProblemReport' + description: '' + tags: + - api + /api/v1/upload/: + post: + operationId: createUploadCreate + description: '' + parameters: [] + requestBody: + content: + application/offset+octet-stream: + schema: + $ref: '#/components/schemas/UploadCreate' + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UploadCreate' + text/csv: + schema: + $ref: '#/components/schemas/UploadCreate' + description: '' + tags: + - api + /api/v1/upload/{guid}/: + put: + operationId: updateUpload + description: '' + parameters: + - name: guid + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/offset+octet-stream: + schema: + $ref: '#/components/schemas/Upload' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Upload' + text/csv: + schema: + $ref: '#/components/schemas/Upload' + description: '' + tags: + - api + patch: + operationId: partialUpdateUpload + description: '' + parameters: + - name: guid + in: path + required: true + description: '' + schema: + type: string + requestBody: + content: + application/offset+octet-stream: + schema: + $ref: '#/components/schemas/Upload' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Upload' + text/csv: + schema: + $ref: '#/components/schemas/Upload' + description: '' + tags: + - api + delete: + operationId: destroyUpload + description: '' + parameters: + - name: guid + in: path + required: true + description: '' + schema: + type: string + responses: + '204': + description: '' + tags: + - api + /api/v1/following/{id}/: + delete: + operationId: destroyFoiRequestFollow + description: '' + parameters: + - name: id + in: path + required: true + description: '' + schema: + type: string + responses: + '204': + description: '' + tags: + - api +components: + schemas: + UserPreference: + type: object + properties: + value: + type: string + required: + - value + FoiRequestList: + type: object + properties: + resource_uri: + type: string + readOnly: true + id: + type: integer + readOnly: true + url: + type: string + readOnly: true + jurisdiction: + type: string + readOnly: true + is_foi: + type: boolean + checked: + type: boolean + refusal_reason: + type: string + maxLength: 1024 + costs: + type: string + readOnly: true + public: + type: boolean + law: + type: string + readOnly: true + description: + type: string + redacted_description: + type: string + readOnly: true + summary: + type: string + same_as_count: + type: integer + maximum: 2147483647 + minimum: -2147483648 + same_as: + type: string + readOnly: true + due_date: + type: string + format: date-time + nullable: true + resolved_on: + type: string + format: date-time + nullable: true + last_message: + type: string + format: date-time + nullable: true + created_at: + type: string + format: date-time + nullable: true + last_modified_at: + type: string + format: date-time + readOnly: true + status: + enum: + - awaiting_user_confirmation + - publicbody_needed + - awaiting_publicbody_confirmation + - awaiting_response + - awaiting_classification + - asleep + - resolved + type: string + public_body: + type: object + properties: + resource_uri: + type: string + readOnly: true + id: + type: integer + name: + type: string + maxLength: 255 + slug: + type: string + maxLength: 255 + pattern: ^[-a-zA-Z0-9_]+$ + other_names: + type: string + description: + type: string + url: + type: string + format: uri + nullable: true + maxLength: 500 + pattern: "^(?:[a-z0-9.+-]*)://(?:[^\\s:@/]+(?::[^\\s:@/]*)?@)?(?:(?:0|25[0-5]|2[0-4][0-9]|1[0-9]?[0-9]?|[1-9][0-9]?)(?:\\\ + .(?:0|25[0-5]|2[0-4][0-9]|1[0-9]?[0-9]?|[1-9][0-9]?)){3}|\\[[0-9a-f:.]+\\\ + ]|([a-z\xA1-\uFFFF0-9](?:[a-z\xA1-\uFFFF0-9-]{0,61}[a-z\xA1-\uFFFF\ + 0-9])?(?:\\.(?!-)[a-z\xA1-\uFFFF0-9-]{1,63}(?( + options?: Options +) => { + return (options?.client ?? client).get< + ListProfilesResponse, + ListProfilesError, + ThrowOnError + >({ + ...options, + url: '/api/v1/user/' + }) +} + +export const retrieveUserPreference = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveUserPreferenceResponse, + RetrieveUserPreferenceError, + ThrowOnError + >({ + ...options, + url: '/api/v1/userpreference/{key}/' + }) +} + +export const createUserPreference = ( + options: Options +) => { + return (options?.client ?? client).post< + CreateUserPreferenceResponse, + CreateUserPreferenceError, + ThrowOnError + >({ + ...options, + url: '/api/v1/userpreference/{key}/' + }) +} + +export const updateUserPreference = ( + options: Options +) => { + return (options?.client ?? client).put< + UpdateUserPreferenceResponse, + UpdateUserPreferenceError, + ThrowOnError + >({ + ...options, + url: '/api/v1/userpreference/{key}/' + }) +} + +export const partialUpdateUserPreference = < + ThrowOnError extends boolean = false +>( + options: Options +) => { + return (options?.client ?? client).patch< + PartialUpdateUserPreferenceResponse, + PartialUpdateUserPreferenceError, + ThrowOnError + >({ + ...options, + url: '/api/v1/userpreference/{key}/' + }) +} + +export const listFoiRequestLists = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListFoiRequestListsResponse, + ListFoiRequestListsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/request/', + responseTransformer: ListFoiRequestListsResponseTransformer + }) +} + +export const createMakeRequest = ( + options?: Options +) => { + return (options?.client ?? client).post< + CreateMakeRequestResponse, + CreateMakeRequestError, + ThrowOnError + >({ + ...options, + url: '/api/v1/request/' + }) +} + +export const searchFoiRequestList = ( + options?: Options +) => { + return (options?.client ?? client).get< + SearchFoiRequestListResponse, + SearchFoiRequestListError, + ThrowOnError + >({ + ...options, + url: '/api/v1/request/search/', + responseTransformer: SearchFoiRequestListResponseTransformer + }) +} + +export const tagsAutocompleteFoiRequestList = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).get< + TagsAutocompleteFoiRequestListResponse, + TagsAutocompleteFoiRequestListError, + ThrowOnError + >({ + ...options, + url: '/api/v1/request/tags/autocomplete/', + responseTransformer: TagsAutocompleteFoiRequestListResponseTransformer + }) +} + +export const retrieveFoiRequestDetail = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveFoiRequestDetailResponse, + RetrieveFoiRequestDetailError, + ThrowOnError + >({ + ...options, + url: '/api/v1/request/{id}/', + responseTransformer: RetrieveFoiRequestDetailResponseTransformer + }) +} + +export const listFoiMessageDrafts = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListFoiMessageDraftsResponse, + ListFoiMessageDraftsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/message/draft/', + responseTransformer: ListFoiMessageDraftsResponseTransformer + }) +} + +export const createFoiMessageDraft = ( + options?: Options +) => { + return (options?.client ?? client).post< + CreateFoiMessageDraftResponse, + CreateFoiMessageDraftError, + ThrowOnError + >({ + ...options, + url: '/api/v1/message/draft/', + responseTransformer: CreateFoiMessageDraftResponseTransformer + }) +} + +export const retrieveFoiMessageDraft = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveFoiMessageDraftResponse, + RetrieveFoiMessageDraftError, + ThrowOnError + >({ + ...options, + url: '/api/v1/message/draft/{id}/', + responseTransformer: RetrieveFoiMessageDraftResponseTransformer + }) +} + +export const updateFoiMessageDraft = ( + options: Options +) => { + return (options?.client ?? client).put< + UpdateFoiMessageDraftResponse, + UpdateFoiMessageDraftError, + ThrowOnError + >({ + ...options, + url: '/api/v1/message/draft/{id}/', + responseTransformer: UpdateFoiMessageDraftResponseTransformer + }) +} + +export const partialUpdateFoiMessageDraft = < + ThrowOnError extends boolean = false +>( + options: Options +) => { + return (options?.client ?? client).patch< + PartialUpdateFoiMessageDraftResponse, + PartialUpdateFoiMessageDraftError, + ThrowOnError + >({ + ...options, + url: '/api/v1/message/draft/{id}/', + responseTransformer: PartialUpdateFoiMessageDraftResponseTransformer + }) +} + +export const destroyFoiMessageDraft = ( + options: Options +) => { + return (options?.client ?? client).delete< + DestroyFoiMessageDraftResponse, + DestroyFoiMessageDraftError, + ThrowOnError + >({ + ...options, + url: '/api/v1/message/draft/{id}/' + }) +} + +export const listFoiMessages = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListFoiMessagesResponse, + ListFoiMessagesError, + ThrowOnError + >({ + ...options, + url: '/api/v1/message/', + responseTransformer: ListFoiMessagesResponseTransformer + }) +} + +export const retrieveFoiMessage = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveFoiMessageResponse, + RetrieveFoiMessageError, + ThrowOnError + >({ + ...options, + url: '/api/v1/message/{id}/', + responseTransformer: RetrieveFoiMessageResponseTransformer + }) +} + +export const listFoiAttachments = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListFoiAttachmentsResponse, + ListFoiAttachmentsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/attachment/', + responseTransformer: ListFoiAttachmentsResponseTransformer + }) +} + +export const createFoiAttachmentTus = ( + options?: Options +) => { + return (options?.client ?? client).post< + CreateFoiAttachmentTusResponse, + CreateFoiAttachmentTusError, + ThrowOnError + >({ + ...options, + url: '/api/v1/attachment/' + }) +} + +export const retrieveFoiAttachment = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveFoiAttachmentResponse, + RetrieveFoiAttachmentError, + ThrowOnError + >({ + ...options, + url: '/api/v1/attachment/{id}/', + responseTransformer: RetrieveFoiAttachmentResponseTransformer + }) +} + +export const listFoiRequestFollows = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListFoiRequestFollowsResponse, + ListFoiRequestFollowsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/following/', + responseTransformer: ListFoiRequestFollowsResponseTransformer + }) +} + +export const createCreateFoiRequestFollow = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).post< + CreateCreateFoiRequestFollowResponse, + CreateCreateFoiRequestFollowError, + ThrowOnError + >({ + ...options, + url: '/api/v1/following/' + }) +} + +export const listGeoRegions = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListGeoRegionsResponse, + ListGeoRegionsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/', + responseTransformer: ListGeoRegionsResponseTransformer + }) +} + +export const autocompleteGeoRegion = ( + options?: Options +) => { + return (options?.client ?? client).get< + AutocompleteGeoRegionResponse, + AutocompleteGeoRegionError, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/autocomplete/', + responseTransformer: AutocompleteGeoRegionResponseTransformer + }) +} + +/** + * This is a OpenRefine Reconciliation API endpoint + */ +export const reconciliationGeoRegion = ( + options?: Options +) => { + return (options?.client ?? client).get< + ReconciliationGeoRegionResponse, + ReconciliationGeoRegionError, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/reconciliation/', + responseTransformer: ReconciliationGeoRegionResponseTransformer + }) +} + +/** + * This is a OpenRefine Reconciliation API endpoint + */ +export const reconciliationGeoRegion1 = ( + options?: Options +) => { + return (options?.client ?? client).post< + ReconciliationGeoRegion1Response, + ReconciliationGeoRegion1Error, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/reconciliation/', + responseTransformer: ReconciliationGeoRegion1ResponseTransformer + }) +} + +/** + * Implements OpenRefine Flyout Entry Point + */ +export const reconciliationFlyoutEntityGeoRegion = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).get< + ReconciliationFlyoutEntityGeoRegionResponse, + ReconciliationFlyoutEntityGeoRegionError, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/reconciliation-flyout/', + responseTransformer: ReconciliationFlyoutEntityGeoRegionResponseTransformer + }) +} + +/** + * Implements OpenRefine Flyout Entry Point + */ +export const reconciliationFlyoutEntityGeoRegion1 = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).post< + ReconciliationFlyoutEntityGeoRegion1Response, + ReconciliationFlyoutEntityGeoRegion1Error, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/reconciliation-flyout/', + responseTransformer: ReconciliationFlyoutEntityGeoRegion1ResponseTransformer + }) +} + +/** + * Implements OpenRefine Data Extension API + */ +export const reconciliationProposePropertiesGeoRegion = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).get< + ReconciliationProposePropertiesGeoRegionResponse, + ReconciliationProposePropertiesGeoRegionError, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/reconciliation-propose-properties/', + responseTransformer: + ReconciliationProposePropertiesGeoRegionResponseTransformer + }) +} + +/** + * Implements OpenRefine Data Extension API + */ +export const reconciliationProposePropertiesGeoRegion1 = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).post< + ReconciliationProposePropertiesGeoRegion1Response, + ReconciliationProposePropertiesGeoRegion1Error, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/reconciliation-propose-properties/', + responseTransformer: + ReconciliationProposePropertiesGeoRegion1ResponseTransformer + }) +} + +/** + * Implements OpenRefine Suggest Entry Point + */ +export const reconciliationSuggestServiceGeoRegion = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).get< + ReconciliationSuggestServiceGeoRegionResponse, + ReconciliationSuggestServiceGeoRegionError, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/reconciliation-suggest-service/', + responseTransformer: + ReconciliationSuggestServiceGeoRegionResponseTransformer + }) +} + +/** + * Implements OpenRefine Suggest Entry Point + */ +export const reconciliationSuggestServiceGeoRegion1 = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).post< + ReconciliationSuggestServiceGeoRegion1Response, + ReconciliationSuggestServiceGeoRegion1Error, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/reconciliation-suggest-service/', + responseTransformer: + ReconciliationSuggestServiceGeoRegion1ResponseTransformer + }) +} + +export const retrieveGeoRegion = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveGeoRegionResponse, + RetrieveGeoRegionError, + ThrowOnError + >({ + ...options, + url: '/api/v1/georegion/{id}/', + responseTransformer: RetrieveGeoRegionResponseTransformer + }) +} + +export const listPublicBodyLists = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListPublicBodyListsResponse, + ListPublicBodyListsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/', + responseTransformer: ListPublicBodyListsResponseTransformer + }) +} + +export const autocompletePublicBodyList = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).get< + AutocompletePublicBodyListResponse, + AutocompletePublicBodyListError, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/autocomplete/', + responseTransformer: AutocompletePublicBodyListResponseTransformer + }) +} + +/** + * This is a OpenRefine Reconciliation API endpoint + */ +export const reconciliationPublicBodyList = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).get< + ReconciliationPublicBodyListResponse, + ReconciliationPublicBodyListError, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/reconciliation/', + responseTransformer: ReconciliationPublicBodyListResponseTransformer + }) +} + +/** + * This is a OpenRefine Reconciliation API endpoint + */ +export const reconciliationPublicBodyList1 = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).post< + ReconciliationPublicBodyList1Response, + ReconciliationPublicBodyList1Error, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/reconciliation/', + responseTransformer: ReconciliationPublicBodyList1ResponseTransformer + }) +} + +/** + * Implements OpenRefine Flyout Entry Point + */ +export const reconciliationFlyoutEntityPublicBodyList = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).get< + ReconciliationFlyoutEntityPublicBodyListResponse, + ReconciliationFlyoutEntityPublicBodyListError, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/reconciliation-flyout/', + responseTransformer: + ReconciliationFlyoutEntityPublicBodyListResponseTransformer + }) +} + +/** + * Implements OpenRefine Flyout Entry Point + */ +export const reconciliationFlyoutEntityPublicBodyList1 = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).post< + ReconciliationFlyoutEntityPublicBodyList1Response, + ReconciliationFlyoutEntityPublicBodyList1Error, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/reconciliation-flyout/', + responseTransformer: + ReconciliationFlyoutEntityPublicBodyList1ResponseTransformer + }) +} + +/** + * Implements OpenRefine Data Extension API + */ +export const reconciliationProposePropertiesPublicBodyList = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).get< + ReconciliationProposePropertiesPublicBodyListResponse, + ReconciliationProposePropertiesPublicBodyListError, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/reconciliation-propose-properties/', + responseTransformer: + ReconciliationProposePropertiesPublicBodyListResponseTransformer + }) +} + +/** + * Implements OpenRefine Data Extension API + */ +export const reconciliationProposePropertiesPublicBodyList1 = < + ThrowOnError extends boolean = false +>( + options?: Options< + ReconciliationProposePropertiesPublicBodyList1Data, + ThrowOnError + > +) => { + return (options?.client ?? client).post< + ReconciliationProposePropertiesPublicBodyList1Response, + ReconciliationProposePropertiesPublicBodyList1Error, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/reconciliation-propose-properties/', + responseTransformer: + ReconciliationProposePropertiesPublicBodyList1ResponseTransformer + }) +} + +/** + * Implements OpenRefine Suggest Entry Point + */ +export const reconciliationSuggestServicePublicBodyList = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).get< + ReconciliationSuggestServicePublicBodyListResponse, + ReconciliationSuggestServicePublicBodyListError, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/reconciliation-suggest-service/', + responseTransformer: + ReconciliationSuggestServicePublicBodyListResponseTransformer + }) +} + +/** + * Implements OpenRefine Suggest Entry Point + */ +export const reconciliationSuggestServicePublicBodyList1 = < + ThrowOnError extends boolean = false +>( + options?: Options< + ReconciliationSuggestServicePublicBodyList1Data, + ThrowOnError + > +) => { + return (options?.client ?? client).post< + ReconciliationSuggestServicePublicBodyList1Response, + ReconciliationSuggestServicePublicBodyList1Error, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/reconciliation-suggest-service/', + responseTransformer: + ReconciliationSuggestServicePublicBodyList1ResponseTransformer + }) +} + +export const searchPublicBodyList = ( + options?: Options +) => { + return (options?.client ?? client).get< + SearchPublicBodyListResponse, + SearchPublicBodyListError, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/search/', + responseTransformer: SearchPublicBodyListResponseTransformer + }) +} + +export const retrievePublicBody = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrievePublicBodyResponse, + RetrievePublicBodyError, + ThrowOnError + >({ + ...options, + url: '/api/v1/publicbody/{id}/', + responseTransformer: RetrievePublicBodyResponseTransformer + }) +} + +export const listCategories = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListCategoriesResponse, + ListCategoriesError, + ThrowOnError + >({ + ...options, + url: '/api/v1/category/' + }) +} + +export const autocompleteCategory = ( + options?: Options +) => { + return (options?.client ?? client).get< + AutocompleteCategoryResponse, + AutocompleteCategoryError, + ThrowOnError + >({ + ...options, + url: '/api/v1/category/autocomplete/' + }) +} + +export const retrieveCategory = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveCategoryResponse, + RetrieveCategoryError, + ThrowOnError + >({ + ...options, + url: '/api/v1/category/{id}/' + }) +} + +export const listClassifications = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListClassificationsResponse, + ListClassificationsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/classification/' + }) +} + +export const retrieveClassification = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveClassificationResponse, + RetrieveClassificationError, + ThrowOnError + >({ + ...options, + url: '/api/v1/classification/{id}/' + }) +} + +export const listJurisdictions = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListJurisdictionsResponse, + ListJurisdictionsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/jurisdiction/', + responseTransformer: ListJurisdictionsResponseTransformer + }) +} + +export const retrieveJurisdiction = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveJurisdictionResponse, + RetrieveJurisdictionError, + ThrowOnError + >({ + ...options, + url: '/api/v1/jurisdiction/{id}/', + responseTransformer: RetrieveJurisdictionResponseTransformer + }) +} + +export const listFoiLaws = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListFoiLawsResponse, + ListFoiLawsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/law/', + responseTransformer: ListFoiLawsResponseTransformer + }) +} + +export const autocompleteFoiLaw = ( + options?: Options +) => { + return (options?.client ?? client).get< + AutocompleteFoiLawResponse, + AutocompleteFoiLawError, + ThrowOnError + >({ + ...options, + url: '/api/v1/law/autocomplete/', + responseTransformer: AutocompleteFoiLawResponseTransformer + }) +} + +export const retrieveFoiLaw = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveFoiLawResponse, + RetrieveFoiLawError, + ThrowOnError + >({ + ...options, + url: '/api/v1/law/{id}/', + responseTransformer: RetrieveFoiLawResponseTransformer + }) +} + +export const listDocuments = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListDocumentsResponse, + ListDocumentsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/document/', + responseTransformer: ListDocumentsResponseTransformer + }) +} + +export const oembedDocument = ( + options?: Options +) => { + return (options?.client ?? client).get< + OembedDocumentResponse, + OembedDocumentError, + ThrowOnError + >({ + ...options, + url: '/api/v1/document/oembed/', + responseTransformer: OembedDocumentResponseTransformer + }) +} + +export const retrieveDocumentDetail = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveDocumentDetailResponse, + RetrieveDocumentDetailError, + ThrowOnError + >({ + ...options, + url: '/api/v1/document/{id}/', + responseTransformer: RetrieveDocumentDetailResponseTransformer + }) +} + +export const updateUpdateDocument = ( + options: Options +) => { + return (options?.client ?? client).put< + UpdateUpdateDocumentResponse, + UpdateUpdateDocumentError, + ThrowOnError + >({ + ...options, + url: '/api/v1/document/{id}/' + }) +} + +export const partialUpdateDocument = ( + options: Options +) => { + return (options?.client ?? client).patch< + PartialUpdateDocumentResponse, + PartialUpdateDocumentError, + ThrowOnError + >({ + ...options, + url: '/api/v1/document/{id}/', + responseTransformer: PartialUpdateDocumentResponseTransformer + }) +} + +export const listDocumentCollections = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListDocumentCollectionsResponse, + ListDocumentCollectionsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/documentcollection/', + responseTransformer: ListDocumentCollectionsResponseTransformer + }) +} + +export const oembedDocumentCollection = ( + options?: Options +) => { + return (options?.client ?? client).get< + OembedDocumentCollectionResponse, + OembedDocumentCollectionError, + ThrowOnError + >({ + ...options, + url: '/api/v1/documentcollection/oembed/', + responseTransformer: OembedDocumentCollectionResponseTransformer + }) +} + +export const retrieveDocumentCollection = < + ThrowOnError extends boolean = false +>( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveDocumentCollectionResponse, + RetrieveDocumentCollectionError, + ThrowOnError + >({ + ...options, + url: '/api/v1/documentcollection/{id}/', + responseTransformer: RetrieveDocumentCollectionResponseTransformer + }) +} + +export const listPages = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListPagesResponse, + ListPagesError, + ThrowOnError + >({ + ...options, + url: '/api/v1/page/' + }) +} + +export const listPageAnnotations = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListPageAnnotationsResponse, + ListPageAnnotationsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/pageannotation/', + responseTransformer: ListPageAnnotationsResponseTransformer + }) +} + +export const createCreatePageAnnotation = < + ThrowOnError extends boolean = false +>( + options?: Options +) => { + return (options?.client ?? client).post< + CreateCreatePageAnnotationResponse, + CreateCreatePageAnnotationError, + ThrowOnError + >({ + ...options, + url: '/api/v1/pageannotation/' + }) +} + +export const retrievePageAnnotation = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrievePageAnnotationResponse, + RetrievePageAnnotationError, + ThrowOnError + >({ + ...options, + url: '/api/v1/pageannotation/{id}/', + responseTransformer: RetrievePageAnnotationResponseTransformer + }) +} + +export const destroyPageAnnotation = ( + options: Options +) => { + return (options?.client ?? client).delete< + DestroyPageAnnotationResponse, + DestroyPageAnnotationError, + ThrowOnError + >({ + ...options, + url: '/api/v1/pageannotation/{id}/' + }) +} + +export const listProblemReports = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListProblemReportsResponse, + ListProblemReportsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/problemreport/', + responseTransformer: ListProblemReportsResponseTransformer + }) +} + +export const retrieveProblemReport = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveProblemReportResponse, + RetrieveProblemReportError, + ThrowOnError + >({ + ...options, + url: '/api/v1/problemreport/{id}/', + responseTransformer: RetrieveProblemReportResponseTransformer + }) +} + +export const listCampaigns = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListCampaignsResponse, + ListCampaignsError, + ThrowOnError + >({ + ...options, + url: '/api/v1/campaign/', + responseTransformer: ListCampaignsResponseTransformer + }) +} + +export const retrieveCampaign = ( + options: Options +) => { + return (options?.client ?? client).get< + RetrieveCampaignResponse, + RetrieveCampaignError, + ThrowOnError + >({ + ...options, + url: '/api/v1/campaign/{id}/', + responseTransformer: RetrieveCampaignResponseTransformer + }) +} + +export const listSpectacularSwaggers = ( + options?: Options +) => { + return (options?.client ?? client).get< + ListSpectacularSwaggersResponse, + ListSpectacularSwaggersError, + ThrowOnError + >({ + ...options, + url: '/api/v1/schema/swagger-ui/' + }) +} + +export const publishFoiMessageDraft = ( + options: Options +) => { + return (options?.client ?? client).post< + PublishFoiMessageDraftResponse, + PublishFoiMessageDraftError, + ThrowOnError + >({ + ...options, + url: '/api/v1/message/draft/{id}/publish/', + responseTransformer: PublishFoiMessageDraftResponseTransformer + }) +} + +export const claimProblemReport = ( + options: Options +) => { + return (options?.client ?? client).post< + ClaimProblemReportResponse, + ClaimProblemReportError, + ThrowOnError + >({ + ...options, + url: '/api/v1/problemreport/{id}/claim/', + responseTransformer: ClaimProblemReportResponseTransformer + }) +} + +export const escalateProblemReport = ( + options: Options +) => { + return (options?.client ?? client).post< + EscalateProblemReportResponse, + EscalateProblemReportError, + ThrowOnError + >({ + ...options, + url: '/api/v1/problemreport/{id}/escalate/', + responseTransformer: EscalateProblemReportResponseTransformer + }) +} + +export const resolveProblemReport = ( + options: Options +) => { + return (options?.client ?? client).post< + ResolveProblemReportResponse, + ResolveProblemReportError, + ThrowOnError + >({ + ...options, + url: '/api/v1/problemreport/{id}/resolve/', + responseTransformer: ResolveProblemReportResponseTransformer + }) +} + +export const unclaimProblemReport = ( + options: Options +) => { + return (options?.client ?? client).post< + UnclaimProblemReportResponse, + UnclaimProblemReportError, + ThrowOnError + >({ + ...options, + url: '/api/v1/problemreport/{id}/unclaim/', + responseTransformer: UnclaimProblemReportResponseTransformer + }) +} + +export const createUploadCreate = ( + options?: Options +) => { + return (options?.client ?? client).post< + CreateUploadCreateResponse, + CreateUploadCreateError, + ThrowOnError + >({ + ...options, + url: '/api/v1/upload/', + responseTransformer: CreateUploadCreateResponseTransformer + }) +} + +export const updateUpload = ( + options: Options +) => { + return (options?.client ?? client).put< + UpdateUploadResponse, + UpdateUploadError, + ThrowOnError + >({ + ...options, + url: '/api/v1/upload/{guid}/', + responseTransformer: UpdateUploadResponseTransformer + }) +} + +export const partialUpdateUpload = ( + options: Options +) => { + return (options?.client ?? client).patch< + PartialUpdateUploadResponse, + PartialUpdateUploadError, + ThrowOnError + >({ + ...options, + url: '/api/v1/upload/{guid}/', + responseTransformer: PartialUpdateUploadResponseTransformer + }) +} + +export const destroyUpload = ( + options: Options +) => { + return (options?.client ?? client).delete< + DestroyUploadResponse, + DestroyUploadError, + ThrowOnError + >({ + ...options, + url: '/api/v1/upload/{guid}/' + }) +} + +export const destroyFoiRequestFollow = ( + options: Options +) => { + return (options?.client ?? client).delete< + DestroyFoiRequestFollowResponse, + DestroyFoiRequestFollowError, + ThrowOnError + >({ + ...options, + url: '/api/v1/following/{id}/' + }) +} diff --git a/frontend/javascript/api/gen/types.gen.ts b/frontend/javascript/api/gen/types.gen.ts new file mode 100644 index 000000000..cb64b403f --- /dev/null +++ b/frontend/javascript/api/gen/types.gen.ts @@ -0,0 +1,3499 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type Campaign = { + readonly resource_uri?: string + readonly id?: number + name: string + slug: string + url?: string + description?: string + start_date?: Date | null + active?: boolean +} + +export type Category = { + readonly id?: number + name: string + slug: string + is_topic?: boolean + depth: number + readonly parent?: string + readonly children?: Array +} + +export type Classification = { + readonly id?: number + name: string + slug: string + depth: number + readonly parent?: string + readonly children?: Array +} + +export type CreateFoiRequestFollow = { + request: number +} + +export type CreatePageAnnotation = { + document: number + page_number: number + title: string + description: string + top?: number | null + left?: number | null + width?: number | null + height?: number | null +} + +export type Document = { + readonly resource_uri?: string + readonly id?: number + readonly site_url?: string + title?: string + slug?: string + description?: string + published_at?: Date | null + num_pages?: number + public?: boolean + listed?: boolean + allow_annotation?: boolean + pending?: boolean + readonly file_url?: string + file_size?: number | null + cover_image: string + page_template: string + outline?: string + properties?: { + [key: string]: unknown + } + readonly uid?: string + data?: { + [key: string]: unknown + } + readonly pages_uri?: string +} + +export type DocumentCollection = { + readonly resource_uri?: string + readonly id?: number + readonly site_url?: string + title?: string + description?: string + public?: boolean + listed?: boolean + created_at?: Date | null + updated_at?: Date | null + readonly document_count?: string + readonly document_directory_count?: string + readonly uid?: string + cover_image: string + readonly directories?: string + readonly documents?: string + readonly documents_uri?: string + readonly pages_uri?: string + settings?: { + [key: string]: unknown + } + readonly zip_download_url?: string +} + +export type DocumentDetail = { + readonly resource_uri?: string + readonly id?: number + readonly site_url?: string + title?: string + slug?: string + description?: string + published_at?: Date | null + num_pages?: number + public?: boolean + listed?: boolean + allow_annotation?: boolean + pending?: boolean + readonly file_url?: string + file_size?: number | null + cover_image: string + page_template: string + outline?: string + properties?: { + [key: string]: unknown + } + readonly uid?: string + data?: { + [key: string]: unknown + } + readonly pages_uri?: string + readonly original?: string + readonly foirequest?: string + readonly publicbody?: string + readonly last_modified_at?: string + readonly pages?: string +} + +export type FoiAttachment = { + readonly resource_uri?: string + readonly id?: number + readonly belongs_to?: string + name: string + filetype?: string + size?: number | null + readonly site_url?: string + readonly anchor_url?: string + readonly file_url?: string + pending?: boolean + is_converted?: boolean + readonly converted?: string + approved?: boolean + can_approve?: boolean + readonly redacted?: string + is_redacted?: boolean + readonly can_redact?: string + readonly can_delete?: string + readonly is_pdf?: string + readonly is_image?: string + readonly is_irrelevant?: string + document: { + readonly resource_uri?: string + readonly id?: number + readonly site_url?: string + title?: string + slug?: string + description?: string + published_at?: Date | null + num_pages?: number + public?: boolean + listed?: boolean + allow_annotation?: boolean + pending?: boolean + readonly file_url?: string + file_size?: number | null + cover_image: string + page_template: string + outline?: string + properties?: { + [key: string]: unknown + } + readonly uid?: string + data?: { + [key: string]: unknown + } + readonly pages_uri?: string + readonly original?: string + readonly foirequest?: string + readonly publicbody?: string + readonly last_modified_at?: string + } +} + +export type FoiAttachmentTus = { + message: string + upload: string +} + +export type FoiLaw = { + readonly resource_uri?: string + readonly id?: number + readonly name?: string + readonly slug?: string + readonly description?: string + readonly long_description?: string + law_type?: string + created?: Date | null + readonly request_note?: string + readonly request_note_html?: string + meta?: boolean + readonly site_url?: string + readonly jurisdiction?: string + email_only?: boolean + readonly mediator?: string + priority?: number + url?: string + max_response_time?: number | null + requires_signature?: boolean + max_response_time_unit?: 'day' | 'working_day' | 'month_de' + readonly letter_start?: string + readonly letter_end?: string + last_modified_at: string + readonly refusal_reasons?: string + readonly combined?: Array +} + +export type max_response_time_unit = 'day' | 'working_day' | 'month_de' + +export const max_response_time_unit = { + DAY: 'day', + WORKING_DAY: 'working_day', + MONTH_DE: 'month_de' +} as const + +export type FoiMessage = { + readonly resource_uri?: string + readonly id?: number + readonly url?: string + request: string + sent?: boolean + is_response?: boolean + readonly is_postal?: string + readonly is_draft?: boolean + kind?: 'email' | 'post' | 'fax' | 'upload' | 'phone' | 'visit' | 'import' + is_escalation?: boolean + content_hidden?: boolean + readonly sender_public_body?: string + readonly recipient_public_body?: string + status?: + | 'awaiting_user_confirmation' + | 'publicbody_needed' + | 'awaiting_publicbody_confirmation' + | 'awaiting_response' + | 'awaiting_classification' + | 'asleep' + | 'resolved' + timestamp?: Date + redacted?: boolean + readonly not_publishable?: boolean + readonly attachments?: string + readonly subject?: string + readonly content?: string + readonly redacted_subject?: string + readonly redacted_content?: string + readonly sender?: string + readonly status_name?: string + readonly last_modified_at?: Date +} + +export type kind = + | 'email' + | 'post' + | 'fax' + | 'upload' + | 'phone' + | 'visit' + | 'import' + +export const kind = { + EMAIL: 'email', + POST: 'post', + FAX: 'fax', + UPLOAD: 'upload', + PHONE: 'phone', + VISIT: 'visit', + IMPORT: 'import' +} as const + +export type status = + | 'awaiting_user_confirmation' + | 'publicbody_needed' + | 'awaiting_publicbody_confirmation' + | 'awaiting_response' + | 'awaiting_classification' + | 'asleep' + | 'resolved' + +export const status = { + AWAITING_USER_CONFIRMATION: 'awaiting_user_confirmation', + PUBLICBODY_NEEDED: 'publicbody_needed', + AWAITING_PUBLICBODY_CONFIRMATION: 'awaiting_publicbody_confirmation', + AWAITING_RESPONSE: 'awaiting_response', + AWAITING_CLASSIFICATION: 'awaiting_classification', + ASLEEP: 'asleep', + RESOLVED: 'resolved' +} as const + +export type FoiMessageDraft = { + readonly resource_uri?: string + readonly id?: number + readonly url?: string + request: string + sent?: boolean + is_response?: boolean + readonly is_postal?: string + readonly is_draft?: boolean + kind?: 'email' | 'post' | 'fax' | 'upload' | 'phone' | 'visit' | 'import' + is_escalation?: boolean + content_hidden?: boolean + readonly sender_public_body?: string + readonly recipient_public_body?: string + status?: + | 'awaiting_user_confirmation' + | 'publicbody_needed' + | 'awaiting_publicbody_confirmation' + | 'awaiting_response' + | 'awaiting_classification' + | 'asleep' + | 'resolved' + timestamp?: Date + redacted?: boolean + readonly not_publishable?: boolean + readonly attachments?: string + readonly subject?: string + readonly content?: string + readonly redacted_subject?: string + readonly redacted_content?: string + readonly sender?: string + readonly status_name?: string + readonly last_modified_at?: Date +} + +export type FoiRequestDetail = { + readonly resource_uri?: string + readonly id?: number + readonly url?: string + readonly jurisdiction?: string + is_foi?: boolean + checked?: boolean + refusal_reason?: string + readonly costs?: string + public?: boolean + readonly law?: { + readonly resource_uri?: string + readonly id?: number + readonly name?: string + readonly slug?: string + readonly description?: string + readonly long_description?: string + law_type?: string + created?: Date | null + readonly request_note?: string + readonly request_note_html?: string + meta?: boolean + readonly site_url?: string + readonly jurisdiction?: string + email_only?: boolean + readonly mediator?: string + priority?: number + url?: string + max_response_time?: number | null + requires_signature?: boolean + max_response_time_unit?: 'day' | 'working_day' | 'month_de' + readonly letter_start?: string + readonly letter_end?: string + last_modified_at: string + readonly refusal_reasons?: string + readonly combined?: Array + } + description: string + readonly redacted_description?: string + summary?: string + same_as_count?: number + readonly same_as?: string + due_date?: Date | null + resolved_on?: Date | null + last_message?: Date | null + created_at?: Date | null + readonly last_modified_at?: Date + status: + | 'awaiting_user_confirmation' + | 'publicbody_needed' + | 'awaiting_publicbody_confirmation' + | 'awaiting_response' + | 'awaiting_classification' + | 'asleep' + | 'resolved' + readonly public_body?: { + readonly resource_uri?: string + id: number + name: string + slug: string + other_names?: string + description?: string + url?: string | null + readonly parent?: string + readonly root?: string + depth?: number + readonly classification?: { + readonly id?: number + name: string + slug: string + depth: number + } + readonly categories?: Array<{ + readonly id?: number + name: string + slug: string + is_topic?: boolean + depth: number + }> + email?: string + contact?: string + address?: string + fax?: string + request_note?: string + number_of_requests?: number + site_url: string + readonly request_note_html?: string + readonly jurisdiction?: { + readonly resource_uri?: string + readonly id?: number + name: string + rank?: number + description?: string + slug: string + site_url: string + readonly region?: string + readonly last_modified_at?: Date + } + readonly laws?: Array<{ + readonly resource_uri?: string + readonly id?: number + readonly name?: string + readonly slug?: string + readonly description?: string + readonly long_description?: string + law_type?: string + created?: Date | null + readonly request_note?: string + readonly request_note_html?: string + meta?: boolean + readonly site_url?: string + readonly jurisdiction?: string + email_only?: boolean + readonly mediator?: string + priority?: number + url?: string + max_response_time?: number | null + requires_signature?: boolean + max_response_time_unit?: 'day' | 'working_day' | 'month_de' + readonly letter_start?: string + readonly letter_end?: string + last_modified_at: string + readonly refusal_reasons?: string + readonly combined?: Array + }> + readonly regions?: Array + source_reference?: string + alternative_emails?: { + [key: string]: unknown + } | null + wikidata_item?: string + extra_data?: { + [key: string]: unknown + } + readonly geo?: string + } + resolution?: + | 'successful' + | 'partially_successful' + | 'not_held' + | 'refused' + | 'user_withdrew_costs' + | 'user_withdrew' + slug: string + title: string + reference?: string + readonly user?: string + readonly project?: string + readonly campaign?: string + tags: string + readonly messages?: string +} + +export type resolution = + | 'successful' + | 'partially_successful' + | 'not_held' + | 'refused' + | 'user_withdrew_costs' + | 'user_withdrew' + +export const resolution = { + SUCCESSFUL: 'successful', + PARTIALLY_SUCCESSFUL: 'partially_successful', + NOT_HELD: 'not_held', + REFUSED: 'refused', + USER_WITHDREW_COSTS: 'user_withdrew_costs', + USER_WITHDREW: 'user_withdrew' +} as const + +export type FoiRequestFollow = { + readonly resource_uri?: string + readonly request?: string + readonly request_url?: string + timestamp?: Date + readonly follow_count?: number + readonly follows?: boolean + readonly can_follow?: boolean +} + +export type FoiRequestList = { + readonly resource_uri?: string + readonly id?: number + readonly url?: string + readonly jurisdiction?: string + is_foi?: boolean + checked?: boolean + refusal_reason?: string + readonly costs?: string + public?: boolean + readonly law?: string + description: string + readonly redacted_description?: string + summary?: string + same_as_count?: number + readonly same_as?: string + due_date?: Date | null + resolved_on?: Date | null + last_message?: Date | null + created_at?: Date | null + readonly last_modified_at?: Date + status: + | 'awaiting_user_confirmation' + | 'publicbody_needed' + | 'awaiting_publicbody_confirmation' + | 'awaiting_response' + | 'awaiting_classification' + | 'asleep' + | 'resolved' + readonly public_body?: { + readonly resource_uri?: string + id: number + name: string + slug: string + other_names?: string + description?: string + url?: string | null + depth?: number + readonly classification?: string + email?: string + contact?: string + address?: string + fax?: string + request_note?: string + number_of_requests?: number + site_url: string + readonly jurisdiction?: string + readonly request_note_html?: string + readonly geo?: string + last_modified_at: string + } + resolution?: + | 'successful' + | 'partially_successful' + | 'not_held' + | 'refused' + | 'user_withdrew_costs' + | 'user_withdrew' + slug: string + title: string + reference?: string + readonly user?: string + readonly project?: string + readonly campaign?: string + tags: string +} + +export type GeoRegion = { + readonly resource_uri?: string + readonly id?: number + name: string + slug: string + kind: + | 'country' + | 'state' + | 'admin_district' + | 'district' + | 'admin_cooperation' + | 'municipality' + | 'borough' + | 'zipcode' + | 'admin_court_jurisdiction' + kind_detail?: string + level?: number + region_identifier?: string + global_identifier?: string + area?: number + population?: number | null + valid_on?: Date | null + readonly part_of?: string + readonly centroid?: string +} + +export type kind2 = + | 'country' + | 'state' + | 'admin_district' + | 'district' + | 'admin_cooperation' + | 'municipality' + | 'borough' + | 'zipcode' + | 'admin_court_jurisdiction' + +export const kind2 = { + COUNTRY: 'country', + STATE: 'state', + ADMIN_DISTRICT: 'admin_district', + DISTRICT: 'district', + ADMIN_COOPERATION: 'admin_cooperation', + MUNICIPALITY: 'municipality', + BOROUGH: 'borough', + ZIPCODE: 'zipcode', + ADMIN_COURT_JURISDICTION: 'admin_court_jurisdiction' +} as const + +export type GeoRegionDetail = { + readonly resource_uri?: string + readonly id?: number + name: string + slug: string + kind: + | 'country' + | 'state' + | 'admin_district' + | 'district' + | 'admin_cooperation' + | 'municipality' + | 'borough' + | 'zipcode' + | 'admin_court_jurisdiction' + kind_detail?: string + level?: number + region_identifier?: string + global_identifier?: string + area?: number + population?: number | null + valid_on?: Date | null + readonly part_of?: string + readonly centroid?: string + readonly geom?: string + readonly gov_seat?: string +} + +export type Jurisdiction = { + readonly resource_uri?: string + readonly id?: number + name: string + rank?: number + description?: string + slug: string + site_url: string + readonly region?: string + readonly last_modified_at?: Date +} + +export type MakeRequest = { + publicbodies: Array + subject: string + body: string + full_text?: boolean + public?: boolean + reference?: string + tags?: Array +} + +export type Page = { + readonly document?: string + number?: number + content?: string + width?: number | null + height?: number | null + image: string + query_highlight: string +} + +export type PageAnnotation = { + readonly id?: number + title?: string + description?: string + top?: number | null + left?: number | null + width?: number | null + height?: number | null + timestamp?: Date + readonly can_delete?: boolean + highlight?: string + image?: Blob | File + readonly document?: string + readonly number?: number +} + +export type ProblemReport = { + readonly id?: number + readonly message_id?: string + kind: + | 'message_not_delivered' + | 'attachment_broken' + | 'redaction_needed' + | 'foi_help_needed' + | 'other' + | 'not_foi' + | 'not_nice' + | 'info_outdated' + | 'info_wrong' + | 'bounce_publicbody' + | 'mail_inauthentic' + readonly kind_label?: string + readonly message_subject?: string + readonly message_url?: string + timestamp?: Date + auto_submitted?: boolean + resolved?: boolean + description?: string + resolution?: string + resolution_timestamp?: Date | null + claimed?: Date | null + readonly related_publicbody_id?: string + escalated?: Date | null + readonly moderator_id?: string + readonly is_requester?: string +} + +export type kind3 = + | 'message_not_delivered' + | 'attachment_broken' + | 'redaction_needed' + | 'foi_help_needed' + | 'other' + | 'not_foi' + | 'not_nice' + | 'info_outdated' + | 'info_wrong' + | 'bounce_publicbody' + | 'mail_inauthentic' + +export const kind3 = { + MESSAGE_NOT_DELIVERED: 'message_not_delivered', + ATTACHMENT_BROKEN: 'attachment_broken', + REDACTION_NEEDED: 'redaction_needed', + FOI_HELP_NEEDED: 'foi_help_needed', + OTHER: 'other', + NOT_FOI: 'not_foi', + NOT_NICE: 'not_nice', + INFO_OUTDATED: 'info_outdated', + INFO_WRONG: 'info_wrong', + BOUNCE_PUBLICBODY: 'bounce_publicbody', + MAIL_INAUTHENTIC: 'mail_inauthentic' +} as const + +export type PublicBody = { + readonly resource_uri?: string + id: number + name: string + slug: string + other_names?: string + description?: string + url?: string | null + readonly parent?: string + readonly root?: string + depth?: number + readonly classification?: { + readonly id?: number + name: string + slug: string + depth: number + } + readonly categories?: Array<{ + readonly id?: number + name: string + slug: string + is_topic?: boolean + depth: number + }> + email?: string + contact?: string + address?: string + fax?: string + request_note?: string + number_of_requests?: number + site_url: string + readonly request_note_html?: string + readonly jurisdiction?: { + readonly resource_uri?: string + readonly id?: number + name: string + rank?: number + description?: string + slug: string + site_url: string + readonly region?: string + readonly last_modified_at?: Date + } + readonly laws?: Array<{ + readonly resource_uri?: string + readonly id?: number + readonly name?: string + readonly slug?: string + readonly description?: string + readonly long_description?: string + law_type?: string + created?: Date | null + readonly request_note?: string + readonly request_note_html?: string + meta?: boolean + readonly site_url?: string + readonly jurisdiction?: string + email_only?: boolean + readonly mediator?: string + priority?: number + url?: string + max_response_time?: number | null + requires_signature?: boolean + max_response_time_unit?: 'day' | 'working_day' | 'month_de' + readonly letter_start?: string + readonly letter_end?: string + last_modified_at: string + readonly refusal_reasons?: string + readonly combined?: Array + }> + readonly regions?: Array + source_reference?: string + alternative_emails?: { + [key: string]: unknown + } | null + wikidata_item?: string + extra_data?: { + [key: string]: unknown + } + readonly geo?: string +} + +export type PublicBodyList = { + readonly resource_uri?: string + id: number + name: string + slug: string + other_names?: string + description?: string + url?: string | null + readonly parent?: string + readonly root?: string + depth?: number + readonly classification?: { + readonly id?: number + name: string + slug: string + depth: number + } + readonly categories?: Array<{ + readonly id?: number + name: string + slug: string + is_topic?: boolean + depth: number + }> + email?: string + contact?: string + address?: string + fax?: string + request_note?: string + number_of_requests?: number + site_url: string + readonly request_note_html?: string + readonly jurisdiction?: { + readonly resource_uri?: string + readonly id?: number + name: string + rank?: number + description?: string + slug: string + site_url: string + readonly region?: string + readonly last_modified_at?: Date + } + readonly laws?: Array + readonly regions?: Array + source_reference?: string + alternative_emails?: { + [key: string]: unknown + } | null + wikidata_item?: string + extra_data?: { + [key: string]: unknown + } + readonly geo?: string +} + +export type UpdateDocument = { + title?: string + description?: string +} + +export type Upload = { + readonly id?: number + guid: string + state?: string + upload_offset?: number + upload_length?: number + upload_metadata?: string + filename?: string + temporary_file_path?: string | null + expires?: Date | null + token?: string | null + user?: number | null +} + +export type UploadCreate = { + readonly id?: number + guid?: string + state?: string + upload_offset?: number + upload_length?: number + upload_metadata?: string + filename?: string + temporary_file_path?: string | null + expires?: Date | null + token?: string | null + user?: number | null +} + +export type UserPreference = { + value: string +} + +export type ListProfilesResponse = Array + +export type ListProfilesError = unknown + +export type RetrieveUserPreferenceData = { + path: { + key: string + } +} + +export type RetrieveUserPreferenceResponse = UserPreference + +export type RetrieveUserPreferenceError = unknown + +export type CreateUserPreferenceData = { + body?: UserPreference + path: { + key: string + } +} + +export type CreateUserPreferenceResponse = UserPreference + +export type CreateUserPreferenceError = unknown + +export type UpdateUserPreferenceData = { + body?: UserPreference + path: { + key: string + } +} + +export type UpdateUserPreferenceResponse = UserPreference + +export type UpdateUserPreferenceError = unknown + +export type PartialUpdateUserPreferenceData = { + body?: UserPreference + path: { + key: string + } +} + +export type PartialUpdateUserPreferenceResponse = UserPreference + +export type PartialUpdateUserPreferenceError = unknown + +export type ListFoiRequestListsData = { + query?: { + /** + * campaign + */ + campaign?: string + /** + * categories + */ + categories?: string + /** + * checked + */ + checked?: string + /** + * classification + */ + classification?: string + /** + * costs + */ + costs?: string + /** + * created_at_after + */ + created_at_after?: string + /** + * created_at_before + */ + created_at_before?: string + /** + * follower + */ + follower?: string + /** + * has_same + */ + has_same?: string + /** + * is_foi + */ + is_foi?: string + /** + * jurisdiction + */ + jurisdiction?: string + /** + * law + */ + law?: string + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + /** + * project + */ + project?: string + /** + * public_body + */ + public_body?: string + /** + * reference + */ + reference?: string + /** + * resolution + */ + resolution?: + | 'successful' + | 'partially_successful' + | 'not_held' + | 'refused' + | 'user_withdrew_costs' + | 'user_withdrew' + /** + * slug + */ + slug?: string + /** + * status + */ + status?: + | 'awaiting_user_confirmation' + | 'publicbody_needed' + | 'awaiting_publicbody_confirmation' + | 'awaiting_response' + | 'awaiting_classification' + | 'asleep' + | 'resolved' + /** + * tags + */ + tags?: string + /** + * user + */ + user?: string + } +} + +export type ListFoiRequestListsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListFoiRequestListsError = unknown + +export type CreateMakeRequestData = { + body?: MakeRequest +} + +export type CreateMakeRequestResponse = MakeRequest + +export type CreateMakeRequestError = unknown + +export type SearchFoiRequestListResponse = FoiRequestList + +export type SearchFoiRequestListError = unknown + +export type TagsAutocompleteFoiRequestListResponse = FoiRequestList + +export type TagsAutocompleteFoiRequestListError = unknown + +export type RetrieveFoiRequestDetailData = { + path: { + id: string + } + query?: { + /** + * campaign + */ + campaign?: string + /** + * categories + */ + categories?: string + /** + * checked + */ + checked?: string + /** + * classification + */ + classification?: string + /** + * costs + */ + costs?: string + /** + * created_at_after + */ + created_at_after?: string + /** + * created_at_before + */ + created_at_before?: string + /** + * follower + */ + follower?: string + /** + * has_same + */ + has_same?: string + /** + * is_foi + */ + is_foi?: string + /** + * jurisdiction + */ + jurisdiction?: string + /** + * law + */ + law?: string + /** + * project + */ + project?: string + /** + * public_body + */ + public_body?: string + /** + * reference + */ + reference?: string + /** + * resolution + */ + resolution?: + | 'successful' + | 'partially_successful' + | 'not_held' + | 'refused' + | 'user_withdrew_costs' + | 'user_withdrew' + /** + * slug + */ + slug?: string + /** + * status + */ + status?: + | 'awaiting_user_confirmation' + | 'publicbody_needed' + | 'awaiting_publicbody_confirmation' + | 'awaiting_response' + | 'awaiting_classification' + | 'asleep' + | 'resolved' + /** + * tags + */ + tags?: string + /** + * user + */ + user?: string + } +} + +export type RetrieveFoiRequestDetailResponse = FoiRequestDetail + +export type RetrieveFoiRequestDetailError = unknown + +export type ListFoiMessageDraftsData = { + query?: { + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + /** + * request + */ + request?: string + } +} + +export type ListFoiMessageDraftsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListFoiMessageDraftsError = unknown + +export type CreateFoiMessageDraftData = { + body?: FoiMessageDraft +} + +export type CreateFoiMessageDraftResponse = FoiMessageDraft + +export type CreateFoiMessageDraftError = unknown + +export type RetrieveFoiMessageDraftData = { + path: { + id: string + } + query?: { + /** + * request + */ + request?: string + } +} + +export type RetrieveFoiMessageDraftResponse = FoiMessageDraft + +export type RetrieveFoiMessageDraftError = unknown + +export type UpdateFoiMessageDraftData = { + body?: FoiMessageDraft + path: { + id: string + } + query?: { + /** + * request + */ + request?: string + } +} + +export type UpdateFoiMessageDraftResponse = FoiMessageDraft + +export type UpdateFoiMessageDraftError = unknown + +export type PartialUpdateFoiMessageDraftData = { + body?: FoiMessageDraft + path: { + id: string + } + query?: { + /** + * request + */ + request?: string + } +} + +export type PartialUpdateFoiMessageDraftResponse = FoiMessageDraft + +export type PartialUpdateFoiMessageDraftError = unknown + +export type DestroyFoiMessageDraftData = { + path: { + id: string + } + query?: { + /** + * request + */ + request?: string + } +} + +export type DestroyFoiMessageDraftResponse = void + +export type DestroyFoiMessageDraftError = unknown + +export type ListFoiMessagesData = { + query?: { + /** + * is_response + */ + is_response?: string + /** + * kind + */ + kind?: 'email' | 'post' | 'fax' | 'upload' | 'phone' | 'visit' | 'import' + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + /** + * request + */ + request?: string + } +} + +export type ListFoiMessagesResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListFoiMessagesError = unknown + +export type RetrieveFoiMessageData = { + path: { + id: string + } + query?: { + /** + * is_response + */ + is_response?: string + /** + * kind + */ + kind?: 'email' | 'post' | 'fax' | 'upload' | 'phone' | 'visit' | 'import' + /** + * request + */ + request?: string + } +} + +export type RetrieveFoiMessageResponse = FoiMessage + +export type RetrieveFoiMessageError = unknown + +export type ListFoiAttachmentsData = { + query?: { + /** + * approved + */ + approved?: string + /** + * belongs_to + */ + belongs_to?: string + /** + * filetype + */ + filetype?: string + /** + * is_redacted + */ + is_redacted?: string + /** + * Number of results to return per page. + */ + limit?: number + /** + * name + */ + name?: string + /** + * The initial index from which to return the results. + */ + offset?: number + } +} + +export type ListFoiAttachmentsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListFoiAttachmentsError = unknown + +export type CreateFoiAttachmentTusData = { + body?: FoiAttachmentTus +} + +export type CreateFoiAttachmentTusResponse = FoiAttachmentTus + +export type CreateFoiAttachmentTusError = unknown + +export type RetrieveFoiAttachmentData = { + path: { + id: string + } + query?: { + /** + * approved + */ + approved?: string + /** + * belongs_to + */ + belongs_to?: string + /** + * filetype + */ + filetype?: string + /** + * is_redacted + */ + is_redacted?: string + /** + * name + */ + name?: string + } +} + +export type RetrieveFoiAttachmentResponse = FoiAttachment + +export type RetrieveFoiAttachmentError = unknown + +export type ListFoiRequestFollowsData = { + query?: { + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + } +} + +export type ListFoiRequestFollowsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListFoiRequestFollowsError = unknown + +export type CreateCreateFoiRequestFollowData = { + body?: CreateFoiRequestFollow +} + +export type CreateCreateFoiRequestFollowResponse = CreateFoiRequestFollow + +export type CreateCreateFoiRequestFollowError = unknown + +export type ListGeoRegionsData = { + query?: { + /** + * ancestor + */ + ancestor?: string + /** + * id + */ + id?: string + /** + * kind + */ + kind?: string + /** + * latlng + */ + latlng?: string + /** + * level + */ + level?: string + /** + * Number of results to return per page. + */ + limit?: number + /** + * name + */ + name?: string + /** + * The initial index from which to return the results. + */ + offset?: number + /** + * q + */ + q?: string + /** + * region_identifier + */ + region_identifier?: string + /** + * slug + */ + slug?: string + } +} + +export type ListGeoRegionsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListGeoRegionsError = unknown + +export type AutocompleteGeoRegionResponse = GeoRegion + +export type AutocompleteGeoRegionError = unknown + +export type ReconciliationGeoRegionResponse = GeoRegion + +export type ReconciliationGeoRegionError = unknown + +export type ReconciliationGeoRegion1Data = { + body?: GeoRegion +} + +export type ReconciliationGeoRegion1Response = GeoRegion + +export type ReconciliationGeoRegion1Error = unknown + +export type ReconciliationFlyoutEntityGeoRegionResponse = GeoRegion + +export type ReconciliationFlyoutEntityGeoRegionError = unknown + +export type ReconciliationFlyoutEntityGeoRegion1Data = { + body?: GeoRegion +} + +export type ReconciliationFlyoutEntityGeoRegion1Response = GeoRegion + +export type ReconciliationFlyoutEntityGeoRegion1Error = unknown + +export type ReconciliationProposePropertiesGeoRegionResponse = GeoRegion + +export type ReconciliationProposePropertiesGeoRegionError = unknown + +export type ReconciliationProposePropertiesGeoRegion1Data = { + body?: GeoRegion +} + +export type ReconciliationProposePropertiesGeoRegion1Response = GeoRegion + +export type ReconciliationProposePropertiesGeoRegion1Error = unknown + +export type ReconciliationSuggestServiceGeoRegionResponse = GeoRegion + +export type ReconciliationSuggestServiceGeoRegionError = unknown + +export type ReconciliationSuggestServiceGeoRegion1Data = { + body?: GeoRegion +} + +export type ReconciliationSuggestServiceGeoRegion1Response = GeoRegion + +export type ReconciliationSuggestServiceGeoRegion1Error = unknown + +export type RetrieveGeoRegionData = { + path: { + /** + * A unique integer value identifying this Geo Region. + */ + id: string + } + query?: { + /** + * ancestor + */ + ancestor?: string + /** + * id + */ + id?: string + /** + * kind + */ + kind?: string + /** + * latlng + */ + latlng?: string + /** + * level + */ + level?: string + /** + * name + */ + name?: string + /** + * q + */ + q?: string + /** + * region_identifier + */ + region_identifier?: string + /** + * slug + */ + slug?: string + } +} + +export type RetrieveGeoRegionResponse = GeoRegionDetail + +export type RetrieveGeoRegionError = unknown + +export type ListPublicBodyListsData = { + query?: { + /** + * category + */ + category?: string + /** + * classification + */ + classification?: string + /** + * classification_id + */ + classification_id?: string + /** + * jurisdiction + */ + jurisdiction?: string + /** + * Number of results to return per page. + */ + limit?: number + /** + * lnglat + */ + lnglat?: string + /** + * The initial index from which to return the results. + */ + offset?: number + /** + * q + */ + q?: string + /** + * regions + */ + regions?: string + /** + * slug + */ + slug?: string + } +} + +export type ListPublicBodyListsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListPublicBodyListsError = unknown + +export type AutocompletePublicBodyListResponse = PublicBodyList + +export type AutocompletePublicBodyListError = unknown + +export type ReconciliationPublicBodyListResponse = PublicBodyList + +export type ReconciliationPublicBodyListError = unknown + +export type ReconciliationPublicBodyList1Data = { + body?: PublicBodyList +} + +export type ReconciliationPublicBodyList1Response = PublicBodyList + +export type ReconciliationPublicBodyList1Error = unknown + +export type ReconciliationFlyoutEntityPublicBodyListResponse = PublicBodyList + +export type ReconciliationFlyoutEntityPublicBodyListError = unknown + +export type ReconciliationFlyoutEntityPublicBodyList1Data = { + body?: PublicBodyList +} + +export type ReconciliationFlyoutEntityPublicBodyList1Response = PublicBodyList + +export type ReconciliationFlyoutEntityPublicBodyList1Error = unknown + +export type ReconciliationProposePropertiesPublicBodyListResponse = + PublicBodyList + +export type ReconciliationProposePropertiesPublicBodyListError = unknown + +export type ReconciliationProposePropertiesPublicBodyList1Data = { + body?: PublicBodyList +} + +export type ReconciliationProposePropertiesPublicBodyList1Response = + PublicBodyList + +export type ReconciliationProposePropertiesPublicBodyList1Error = unknown + +export type ReconciliationSuggestServicePublicBodyListResponse = PublicBodyList + +export type ReconciliationSuggestServicePublicBodyListError = unknown + +export type ReconciliationSuggestServicePublicBodyList1Data = { + body?: PublicBodyList +} + +export type ReconciliationSuggestServicePublicBodyList1Response = PublicBodyList + +export type ReconciliationSuggestServicePublicBodyList1Error = unknown + +export type SearchPublicBodyListResponse = PublicBodyList + +export type SearchPublicBodyListError = unknown + +export type RetrievePublicBodyData = { + path: { + id: string + } + query?: { + /** + * category + */ + category?: string + /** + * classification + */ + classification?: string + /** + * classification_id + */ + classification_id?: string + /** + * jurisdiction + */ + jurisdiction?: string + /** + * lnglat + */ + lnglat?: string + /** + * q + */ + q?: string + /** + * regions + */ + regions?: string + /** + * slug + */ + slug?: string + } +} + +export type RetrievePublicBodyResponse = PublicBody + +export type RetrievePublicBodyError = unknown + +export type ListCategoriesData = { + query?: { + /** + * ancestor + */ + ancestor?: string + /** + * depth + */ + depth?: string + /** + * is_topic + */ + is_topic?: string + /** + * Number of results to return per page. + */ + limit?: number + /** + * name + */ + name?: string + /** + * The initial index from which to return the results. + */ + offset?: number + /** + * parent + */ + parent?: string + /** + * q + */ + q?: string + } +} + +export type ListCategoriesResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListCategoriesError = unknown + +export type AutocompleteCategoryResponse = Category + +export type AutocompleteCategoryError = unknown + +export type RetrieveCategoryData = { + path: { + /** + * A unique integer value identifying this category. + */ + id: string + } + query?: { + /** + * ancestor + */ + ancestor?: string + /** + * depth + */ + depth?: string + /** + * is_topic + */ + is_topic?: string + /** + * name + */ + name?: string + /** + * parent + */ + parent?: string + /** + * q + */ + q?: string + } +} + +export type RetrieveCategoryResponse = Category + +export type RetrieveCategoryError = unknown + +export type ListClassificationsData = { + query?: { + /** + * ancestor + */ + ancestor?: string + /** + * depth + */ + depth?: string + /** + * Number of results to return per page. + */ + limit?: number + /** + * name + */ + name?: string + /** + * The initial index from which to return the results. + */ + offset?: number + /** + * parent + */ + parent?: string + /** + * q + */ + q?: string + } +} + +export type ListClassificationsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListClassificationsError = unknown + +export type RetrieveClassificationData = { + path: { + /** + * A unique integer value identifying this Classification. + */ + id: string + } + query?: { + /** + * ancestor + */ + ancestor?: string + /** + * depth + */ + depth?: string + /** + * name + */ + name?: string + /** + * parent + */ + parent?: string + /** + * q + */ + q?: string + } +} + +export type RetrieveClassificationResponse = Classification + +export type RetrieveClassificationError = unknown + +export type ListJurisdictionsData = { + query?: { + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + } +} + +export type ListJurisdictionsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListJurisdictionsError = unknown + +export type RetrieveJurisdictionData = { + path: { + /** + * A unique integer value identifying this Jurisdiction. + */ + id: string + } +} + +export type RetrieveJurisdictionResponse = Jurisdiction + +export type RetrieveJurisdictionError = unknown + +export type ListFoiLawsData = { + query?: { + /** + * id + */ + id?: string + /** + * jurisdiction + */ + jurisdiction?: string + /** + * Number of results to return per page. + */ + limit?: number + /** + * mediator + */ + mediator?: string + /** + * meta + */ + meta?: string + /** + * The initial index from which to return the results. + */ + offset?: number + /** + * q + */ + q?: string + } +} + +export type ListFoiLawsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListFoiLawsError = unknown + +export type AutocompleteFoiLawResponse = FoiLaw + +export type AutocompleteFoiLawError = unknown + +export type RetrieveFoiLawData = { + path: { + /** + * A unique integer value identifying this Freedom of Information Law. + */ + id: string + } + query?: { + /** + * id + */ + id?: string + /** + * jurisdiction + */ + jurisdiction?: string + /** + * mediator + */ + mediator?: string + /** + * meta + */ + meta?: string + /** + * q + */ + q?: string + } +} + +export type RetrieveFoiLawResponse = FoiLaw + +export type RetrieveFoiLawError = unknown + +export type ListDocumentsData = { + query?: { + /** + * collection + */ + collection?: string + /** + * created_at + */ + created_at?: string + /** + * directory + */ + directory?: string + /** + * foirequest + */ + foirequest?: string + /** + * ids + */ + ids?: string + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + /** + * portal + */ + portal?: string + /** + * publicbody + */ + publicbody?: string + /** + * tag + */ + tag?: string + } +} + +export type ListDocumentsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListDocumentsError = unknown + +export type OembedDocumentResponse = Document + +export type OembedDocumentError = unknown + +export type RetrieveDocumentDetailData = { + path: { + id: string + } + query?: { + /** + * collection + */ + collection?: string + /** + * created_at + */ + created_at?: string + /** + * directory + */ + directory?: string + /** + * foirequest + */ + foirequest?: string + /** + * ids + */ + ids?: string + /** + * portal + */ + portal?: string + /** + * publicbody + */ + publicbody?: string + /** + * tag + */ + tag?: string + } +} + +export type RetrieveDocumentDetailResponse = DocumentDetail + +export type RetrieveDocumentDetailError = unknown + +export type UpdateUpdateDocumentData = { + body?: UpdateDocument + path: { + id: string + } + query?: { + /** + * collection + */ + collection?: string + /** + * created_at + */ + created_at?: string + /** + * directory + */ + directory?: string + /** + * foirequest + */ + foirequest?: string + /** + * ids + */ + ids?: string + /** + * portal + */ + portal?: string + /** + * publicbody + */ + publicbody?: string + /** + * tag + */ + tag?: string + } +} + +export type UpdateUpdateDocumentResponse = UpdateDocument + +export type UpdateUpdateDocumentError = unknown + +export type PartialUpdateDocumentData = { + body?: Document + path: { + id: string + } + query?: { + /** + * collection + */ + collection?: string + /** + * created_at + */ + created_at?: string + /** + * directory + */ + directory?: string + /** + * foirequest + */ + foirequest?: string + /** + * ids + */ + ids?: string + /** + * portal + */ + portal?: string + /** + * publicbody + */ + publicbody?: string + /** + * tag + */ + tag?: string + } +} + +export type PartialUpdateDocumentResponse = Document + +export type PartialUpdateDocumentError = unknown + +export type ListDocumentCollectionsData = { + query?: { + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + } +} + +export type ListDocumentCollectionsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListDocumentCollectionsError = unknown + +export type OembedDocumentCollectionResponse = DocumentCollection + +export type OembedDocumentCollectionError = unknown + +export type RetrieveDocumentCollectionData = { + path: { + id: string + } +} + +export type RetrieveDocumentCollectionResponse = DocumentCollection + +export type RetrieveDocumentCollectionError = unknown + +export type ListPagesData = { + query?: { + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + } +} + +export type ListPagesResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListPagesError = unknown + +export type ListPageAnnotationsData = { + query?: { + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + } +} + +export type ListPageAnnotationsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListPageAnnotationsError = unknown + +export type CreateCreatePageAnnotationData = { + body?: CreatePageAnnotation +} + +export type CreateCreatePageAnnotationResponse = CreatePageAnnotation + +export type CreateCreatePageAnnotationError = unknown + +export type RetrievePageAnnotationData = { + path: { + id: string + } +} + +export type RetrievePageAnnotationResponse = PageAnnotation + +export type RetrievePageAnnotationError = unknown + +export type DestroyPageAnnotationData = { + path: { + id: string + } +} + +export type DestroyPageAnnotationResponse = void + +export type DestroyPageAnnotationError = unknown + +export type ListProblemReportsData = { + query?: { + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + } +} + +export type ListProblemReportsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListProblemReportsError = unknown + +export type RetrieveProblemReportData = { + path: { + id: string + } +} + +export type RetrieveProblemReportResponse = ProblemReport + +export type RetrieveProblemReportError = unknown + +export type ListCampaignsData = { + query?: { + /** + * Number of results to return per page. + */ + limit?: number + /** + * The initial index from which to return the results. + */ + offset?: number + } +} + +export type ListCampaignsResponse = { + count: number + next?: string | null + previous?: string | null + results: Array +} + +export type ListCampaignsError = unknown + +export type RetrieveCampaignData = { + path: { + /** + * A unique integer value identifying this campaign. + */ + id: string + } +} + +export type RetrieveCampaignResponse = Campaign + +export type RetrieveCampaignError = unknown + +export type ListSpectacularSwaggersResponse = Array + +export type ListSpectacularSwaggersError = unknown + +export type PublishFoiMessageDraftData = { + body?: FoiMessageDraft + path: { + id: string + } +} + +export type PublishFoiMessageDraftResponse = FoiMessageDraft + +export type PublishFoiMessageDraftError = unknown + +export type ClaimProblemReportData = { + body?: ProblemReport + path: { + id: string + } +} + +export type ClaimProblemReportResponse = ProblemReport + +export type ClaimProblemReportError = unknown + +export type EscalateProblemReportData = { + body?: ProblemReport + path: { + id: string + } +} + +export type EscalateProblemReportResponse = ProblemReport + +export type EscalateProblemReportError = unknown + +export type ResolveProblemReportData = { + body?: ProblemReport + path: { + id: string + } +} + +export type ResolveProblemReportResponse = ProblemReport + +export type ResolveProblemReportError = unknown + +export type UnclaimProblemReportData = { + body?: ProblemReport + path: { + id: string + } +} + +export type UnclaimProblemReportResponse = ProblemReport + +export type UnclaimProblemReportError = unknown + +export type CreateUploadCreateData = { + body?: UploadCreate +} + +export type CreateUploadCreateResponse = UploadCreate + +export type CreateUploadCreateError = unknown + +export type UpdateUploadData = { + body?: Upload + path: { + guid: string + } +} + +export type UpdateUploadResponse = Upload + +export type UpdateUploadError = unknown + +export type PartialUpdateUploadData = { + body?: Upload + path: { + guid: string + } +} + +export type PartialUpdateUploadResponse = Upload + +export type PartialUpdateUploadError = unknown + +export type DestroyUploadData = { + path: { + guid: string + } +} + +export type DestroyUploadResponse = void + +export type DestroyUploadError = unknown + +export type DestroyFoiRequestFollowData = { + path: { + id: string + } +} + +export type DestroyFoiRequestFollowResponse = void + +export type DestroyFoiRequestFollowError = unknown + +export type ListFoiRequestListsResponseTransformer = ( + data: any +) => Promise + +export type FoiRequestListModelResponseTransformer = ( + data: any +) => FoiRequestList + +export const FoiRequestListModelResponseTransformer: FoiRequestListModelResponseTransformer = + (data) => { + if (data?.due_date) { + data.due_date = new Date(data.due_date) + } + if (data?.resolved_on) { + data.resolved_on = new Date(data.resolved_on) + } + if (data?.last_message) { + data.last_message = new Date(data.last_message) + } + if (data?.created_at) { + data.created_at = new Date(data.created_at) + } + if (data?.last_modified_at) { + data.last_modified_at = new Date(data.last_modified_at) + } + return data + } + +export const ListFoiRequestListsResponseTransformer: ListFoiRequestListsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(FoiRequestListModelResponseTransformer) + } + return data + } + +export type SearchFoiRequestListResponseTransformer = ( + data: any +) => Promise + +export const SearchFoiRequestListResponseTransformer: SearchFoiRequestListResponseTransformer = + async (data) => { + FoiRequestListModelResponseTransformer(data) + return data + } + +export type TagsAutocompleteFoiRequestListResponseTransformer = ( + data: any +) => Promise + +export const TagsAutocompleteFoiRequestListResponseTransformer: TagsAutocompleteFoiRequestListResponseTransformer = + async (data) => { + FoiRequestListModelResponseTransformer(data) + return data + } + +export type RetrieveFoiRequestDetailResponseTransformer = ( + data: any +) => Promise + +export type FoiRequestDetailModelResponseTransformer = ( + data: any +) => FoiRequestDetail + +export const FoiRequestDetailModelResponseTransformer: FoiRequestDetailModelResponseTransformer = + (data) => { + if (data?.law?.created) { + data.law.created = new Date(data.law.created) + } + if (data?.due_date) { + data.due_date = new Date(data.due_date) + } + if (data?.resolved_on) { + data.resolved_on = new Date(data.resolved_on) + } + if (data?.last_message) { + data.last_message = new Date(data.last_message) + } + if (data?.created_at) { + data.created_at = new Date(data.created_at) + } + if (data?.last_modified_at) { + data.last_modified_at = new Date(data.last_modified_at) + } + if (data?.public_body?.jurisdiction?.last_modified_at) { + data.public_body.jurisdiction.last_modified_at = new Date( + data.public_body.jurisdiction.last_modified_at + ) + } + return data + } + +export const RetrieveFoiRequestDetailResponseTransformer: RetrieveFoiRequestDetailResponseTransformer = + async (data) => { + FoiRequestDetailModelResponseTransformer(data) + return data + } + +export type ListFoiMessageDraftsResponseTransformer = ( + data: any +) => Promise + +export type FoiMessageDraftModelResponseTransformer = ( + data: any +) => FoiMessageDraft + +export const FoiMessageDraftModelResponseTransformer: FoiMessageDraftModelResponseTransformer = + (data) => { + if (data?.timestamp) { + data.timestamp = new Date(data.timestamp) + } + if (data?.last_modified_at) { + data.last_modified_at = new Date(data.last_modified_at) + } + return data + } + +export const ListFoiMessageDraftsResponseTransformer: ListFoiMessageDraftsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(FoiMessageDraftModelResponseTransformer) + } + return data + } + +export type CreateFoiMessageDraftResponseTransformer = ( + data: any +) => Promise + +export const CreateFoiMessageDraftResponseTransformer: CreateFoiMessageDraftResponseTransformer = + async (data) => { + FoiMessageDraftModelResponseTransformer(data) + return data + } + +export type RetrieveFoiMessageDraftResponseTransformer = ( + data: any +) => Promise + +export const RetrieveFoiMessageDraftResponseTransformer: RetrieveFoiMessageDraftResponseTransformer = + async (data) => { + FoiMessageDraftModelResponseTransformer(data) + return data + } + +export type UpdateFoiMessageDraftResponseTransformer = ( + data: any +) => Promise + +export const UpdateFoiMessageDraftResponseTransformer: UpdateFoiMessageDraftResponseTransformer = + async (data) => { + FoiMessageDraftModelResponseTransformer(data) + return data + } + +export type PartialUpdateFoiMessageDraftResponseTransformer = ( + data: any +) => Promise + +export const PartialUpdateFoiMessageDraftResponseTransformer: PartialUpdateFoiMessageDraftResponseTransformer = + async (data) => { + FoiMessageDraftModelResponseTransformer(data) + return data + } + +export type ListFoiMessagesResponseTransformer = ( + data: any +) => Promise + +export type FoiMessageModelResponseTransformer = (data: any) => FoiMessage + +export const FoiMessageModelResponseTransformer: FoiMessageModelResponseTransformer = + (data) => { + if (data?.timestamp) { + data.timestamp = new Date(data.timestamp) + } + if (data?.last_modified_at) { + data.last_modified_at = new Date(data.last_modified_at) + } + return data + } + +export const ListFoiMessagesResponseTransformer: ListFoiMessagesResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(FoiMessageModelResponseTransformer) + } + return data + } + +export type RetrieveFoiMessageResponseTransformer = ( + data: any +) => Promise + +export const RetrieveFoiMessageResponseTransformer: RetrieveFoiMessageResponseTransformer = + async (data) => { + FoiMessageModelResponseTransformer(data) + return data + } + +export type ListFoiAttachmentsResponseTransformer = ( + data: any +) => Promise + +export type FoiAttachmentModelResponseTransformer = (data: any) => FoiAttachment + +export const FoiAttachmentModelResponseTransformer: FoiAttachmentModelResponseTransformer = + (data) => { + if (data?.document?.published_at) { + data.document.published_at = new Date(data.document.published_at) + } + return data + } + +export const ListFoiAttachmentsResponseTransformer: ListFoiAttachmentsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(FoiAttachmentModelResponseTransformer) + } + return data + } + +export type RetrieveFoiAttachmentResponseTransformer = ( + data: any +) => Promise + +export const RetrieveFoiAttachmentResponseTransformer: RetrieveFoiAttachmentResponseTransformer = + async (data) => { + FoiAttachmentModelResponseTransformer(data) + return data + } + +export type ListFoiRequestFollowsResponseTransformer = ( + data: any +) => Promise + +export type FoiRequestFollowModelResponseTransformer = ( + data: any +) => FoiRequestFollow + +export const FoiRequestFollowModelResponseTransformer: FoiRequestFollowModelResponseTransformer = + (data) => { + if (data?.timestamp) { + data.timestamp = new Date(data.timestamp) + } + return data + } + +export const ListFoiRequestFollowsResponseTransformer: ListFoiRequestFollowsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(FoiRequestFollowModelResponseTransformer) + } + return data + } + +export type ListGeoRegionsResponseTransformer = ( + data: any +) => Promise + +export type GeoRegionModelResponseTransformer = (data: any) => GeoRegion + +export const GeoRegionModelResponseTransformer: GeoRegionModelResponseTransformer = + (data) => { + if (data?.valid_on) { + data.valid_on = new Date(data.valid_on) + } + return data + } + +export const ListGeoRegionsResponseTransformer: ListGeoRegionsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(GeoRegionModelResponseTransformer) + } + return data + } + +export type AutocompleteGeoRegionResponseTransformer = ( + data: any +) => Promise + +export const AutocompleteGeoRegionResponseTransformer: AutocompleteGeoRegionResponseTransformer = + async (data) => { + GeoRegionModelResponseTransformer(data) + return data + } + +export type ReconciliationGeoRegionResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationGeoRegionResponseTransformer: ReconciliationGeoRegionResponseTransformer = + async (data) => { + GeoRegionModelResponseTransformer(data) + return data + } + +export type ReconciliationGeoRegion1ResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationGeoRegion1ResponseTransformer: ReconciliationGeoRegion1ResponseTransformer = + async (data) => { + GeoRegionModelResponseTransformer(data) + return data + } + +export type ReconciliationFlyoutEntityGeoRegionResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationFlyoutEntityGeoRegionResponseTransformer: ReconciliationFlyoutEntityGeoRegionResponseTransformer = + async (data) => { + GeoRegionModelResponseTransformer(data) + return data + } + +export type ReconciliationFlyoutEntityGeoRegion1ResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationFlyoutEntityGeoRegion1ResponseTransformer: ReconciliationFlyoutEntityGeoRegion1ResponseTransformer = + async (data) => { + GeoRegionModelResponseTransformer(data) + return data + } + +export type ReconciliationProposePropertiesGeoRegionResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationProposePropertiesGeoRegionResponseTransformer: ReconciliationProposePropertiesGeoRegionResponseTransformer = + async (data) => { + GeoRegionModelResponseTransformer(data) + return data + } + +export type ReconciliationProposePropertiesGeoRegion1ResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationProposePropertiesGeoRegion1ResponseTransformer: ReconciliationProposePropertiesGeoRegion1ResponseTransformer = + async (data) => { + GeoRegionModelResponseTransformer(data) + return data + } + +export type ReconciliationSuggestServiceGeoRegionResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationSuggestServiceGeoRegionResponseTransformer: ReconciliationSuggestServiceGeoRegionResponseTransformer = + async (data) => { + GeoRegionModelResponseTransformer(data) + return data + } + +export type ReconciliationSuggestServiceGeoRegion1ResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationSuggestServiceGeoRegion1ResponseTransformer: ReconciliationSuggestServiceGeoRegion1ResponseTransformer = + async (data) => { + GeoRegionModelResponseTransformer(data) + return data + } + +export type RetrieveGeoRegionResponseTransformer = ( + data: any +) => Promise + +export type GeoRegionDetailModelResponseTransformer = ( + data: any +) => GeoRegionDetail + +export const GeoRegionDetailModelResponseTransformer: GeoRegionDetailModelResponseTransformer = + (data) => { + if (data?.valid_on) { + data.valid_on = new Date(data.valid_on) + } + return data + } + +export const RetrieveGeoRegionResponseTransformer: RetrieveGeoRegionResponseTransformer = + async (data) => { + GeoRegionDetailModelResponseTransformer(data) + return data + } + +export type ListPublicBodyListsResponseTransformer = ( + data: any +) => Promise + +export type PublicBodyListModelResponseTransformer = ( + data: any +) => PublicBodyList + +export const PublicBodyListModelResponseTransformer: PublicBodyListModelResponseTransformer = + (data) => { + if (data?.jurisdiction?.last_modified_at) { + data.jurisdiction.last_modified_at = new Date( + data.jurisdiction.last_modified_at + ) + } + return data + } + +export const ListPublicBodyListsResponseTransformer: ListPublicBodyListsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(PublicBodyListModelResponseTransformer) + } + return data + } + +export type AutocompletePublicBodyListResponseTransformer = ( + data: any +) => Promise + +export const AutocompletePublicBodyListResponseTransformer: AutocompletePublicBodyListResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type ReconciliationPublicBodyListResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationPublicBodyListResponseTransformer: ReconciliationPublicBodyListResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type ReconciliationPublicBodyList1ResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationPublicBodyList1ResponseTransformer: ReconciliationPublicBodyList1ResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type ReconciliationFlyoutEntityPublicBodyListResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationFlyoutEntityPublicBodyListResponseTransformer: ReconciliationFlyoutEntityPublicBodyListResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type ReconciliationFlyoutEntityPublicBodyList1ResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationFlyoutEntityPublicBodyList1ResponseTransformer: ReconciliationFlyoutEntityPublicBodyList1ResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type ReconciliationProposePropertiesPublicBodyListResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationProposePropertiesPublicBodyListResponseTransformer: ReconciliationProposePropertiesPublicBodyListResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type ReconciliationProposePropertiesPublicBodyList1ResponseTransformer = + (data: any) => Promise + +export const ReconciliationProposePropertiesPublicBodyList1ResponseTransformer: ReconciliationProposePropertiesPublicBodyList1ResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type ReconciliationSuggestServicePublicBodyListResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationSuggestServicePublicBodyListResponseTransformer: ReconciliationSuggestServicePublicBodyListResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type ReconciliationSuggestServicePublicBodyList1ResponseTransformer = ( + data: any +) => Promise + +export const ReconciliationSuggestServicePublicBodyList1ResponseTransformer: ReconciliationSuggestServicePublicBodyList1ResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type SearchPublicBodyListResponseTransformer = ( + data: any +) => Promise + +export const SearchPublicBodyListResponseTransformer: SearchPublicBodyListResponseTransformer = + async (data) => { + PublicBodyListModelResponseTransformer(data) + return data + } + +export type RetrievePublicBodyResponseTransformer = ( + data: any +) => Promise + +export type PublicBodyModelResponseTransformer = (data: any) => PublicBody + +export const PublicBodyModelResponseTransformer: PublicBodyModelResponseTransformer = + (data) => { + if (data?.jurisdiction?.last_modified_at) { + data.jurisdiction.last_modified_at = new Date( + data.jurisdiction.last_modified_at + ) + } + return data + } + +export const RetrievePublicBodyResponseTransformer: RetrievePublicBodyResponseTransformer = + async (data) => { + PublicBodyModelResponseTransformer(data) + return data + } + +export type ListJurisdictionsResponseTransformer = ( + data: any +) => Promise + +export type JurisdictionModelResponseTransformer = (data: any) => Jurisdiction + +export const JurisdictionModelResponseTransformer: JurisdictionModelResponseTransformer = + (data) => { + if (data?.last_modified_at) { + data.last_modified_at = new Date(data.last_modified_at) + } + return data + } + +export const ListJurisdictionsResponseTransformer: ListJurisdictionsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(JurisdictionModelResponseTransformer) + } + return data + } + +export type RetrieveJurisdictionResponseTransformer = ( + data: any +) => Promise + +export const RetrieveJurisdictionResponseTransformer: RetrieveJurisdictionResponseTransformer = + async (data) => { + JurisdictionModelResponseTransformer(data) + return data + } + +export type ListFoiLawsResponseTransformer = ( + data: any +) => Promise + +export type FoiLawModelResponseTransformer = (data: any) => FoiLaw + +export const FoiLawModelResponseTransformer: FoiLawModelResponseTransformer = ( + data +) => { + if (data?.created) { + data.created = new Date(data.created) + } + return data +} + +export const ListFoiLawsResponseTransformer: ListFoiLawsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(FoiLawModelResponseTransformer) + } + return data + } + +export type AutocompleteFoiLawResponseTransformer = ( + data: any +) => Promise + +export const AutocompleteFoiLawResponseTransformer: AutocompleteFoiLawResponseTransformer = + async (data) => { + FoiLawModelResponseTransformer(data) + return data + } + +export type RetrieveFoiLawResponseTransformer = ( + data: any +) => Promise + +export const RetrieveFoiLawResponseTransformer: RetrieveFoiLawResponseTransformer = + async (data) => { + FoiLawModelResponseTransformer(data) + return data + } + +export type ListDocumentsResponseTransformer = ( + data: any +) => Promise + +export type DocumentModelResponseTransformer = (data: any) => Document + +export const DocumentModelResponseTransformer: DocumentModelResponseTransformer = + (data) => { + if (data?.published_at) { + data.published_at = new Date(data.published_at) + } + return data + } + +export const ListDocumentsResponseTransformer: ListDocumentsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(DocumentModelResponseTransformer) + } + return data + } + +export type OembedDocumentResponseTransformer = ( + data: any +) => Promise + +export const OembedDocumentResponseTransformer: OembedDocumentResponseTransformer = + async (data) => { + DocumentModelResponseTransformer(data) + return data + } + +export type RetrieveDocumentDetailResponseTransformer = ( + data: any +) => Promise + +export type DocumentDetailModelResponseTransformer = ( + data: any +) => DocumentDetail + +export const DocumentDetailModelResponseTransformer: DocumentDetailModelResponseTransformer = + (data) => { + if (data?.published_at) { + data.published_at = new Date(data.published_at) + } + return data + } + +export const RetrieveDocumentDetailResponseTransformer: RetrieveDocumentDetailResponseTransformer = + async (data) => { + DocumentDetailModelResponseTransformer(data) + return data + } + +export type PartialUpdateDocumentResponseTransformer = ( + data: any +) => Promise + +export const PartialUpdateDocumentResponseTransformer: PartialUpdateDocumentResponseTransformer = + async (data) => { + DocumentModelResponseTransformer(data) + return data + } + +export type ListDocumentCollectionsResponseTransformer = ( + data: any +) => Promise + +export type DocumentCollectionModelResponseTransformer = ( + data: any +) => DocumentCollection + +export const DocumentCollectionModelResponseTransformer: DocumentCollectionModelResponseTransformer = + (data) => { + if (data?.created_at) { + data.created_at = new Date(data.created_at) + } + if (data?.updated_at) { + data.updated_at = new Date(data.updated_at) + } + return data + } + +export const ListDocumentCollectionsResponseTransformer: ListDocumentCollectionsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(DocumentCollectionModelResponseTransformer) + } + return data + } + +export type OembedDocumentCollectionResponseTransformer = ( + data: any +) => Promise + +export const OembedDocumentCollectionResponseTransformer: OembedDocumentCollectionResponseTransformer = + async (data) => { + DocumentCollectionModelResponseTransformer(data) + return data + } + +export type RetrieveDocumentCollectionResponseTransformer = ( + data: any +) => Promise + +export const RetrieveDocumentCollectionResponseTransformer: RetrieveDocumentCollectionResponseTransformer = + async (data) => { + DocumentCollectionModelResponseTransformer(data) + return data + } + +export type ListPageAnnotationsResponseTransformer = ( + data: any +) => Promise + +export type PageAnnotationModelResponseTransformer = ( + data: any +) => PageAnnotation + +export const PageAnnotationModelResponseTransformer: PageAnnotationModelResponseTransformer = + (data) => { + if (data?.timestamp) { + data.timestamp = new Date(data.timestamp) + } + return data + } + +export const ListPageAnnotationsResponseTransformer: ListPageAnnotationsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(PageAnnotationModelResponseTransformer) + } + return data + } + +export type RetrievePageAnnotationResponseTransformer = ( + data: any +) => Promise + +export const RetrievePageAnnotationResponseTransformer: RetrievePageAnnotationResponseTransformer = + async (data) => { + PageAnnotationModelResponseTransformer(data) + return data + } + +export type ListProblemReportsResponseTransformer = ( + data: any +) => Promise + +export type ProblemReportModelResponseTransformer = (data: any) => ProblemReport + +export const ProblemReportModelResponseTransformer: ProblemReportModelResponseTransformer = + (data) => { + if (data?.timestamp) { + data.timestamp = new Date(data.timestamp) + } + if (data?.resolution_timestamp) { + data.resolution_timestamp = new Date(data.resolution_timestamp) + } + if (data?.claimed) { + data.claimed = new Date(data.claimed) + } + if (data?.escalated) { + data.escalated = new Date(data.escalated) + } + return data + } + +export const ListProblemReportsResponseTransformer: ListProblemReportsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(ProblemReportModelResponseTransformer) + } + return data + } + +export type RetrieveProblemReportResponseTransformer = ( + data: any +) => Promise + +export const RetrieveProblemReportResponseTransformer: RetrieveProblemReportResponseTransformer = + async (data) => { + ProblemReportModelResponseTransformer(data) + return data + } + +export type ListCampaignsResponseTransformer = ( + data: any +) => Promise + +export type CampaignModelResponseTransformer = (data: any) => Campaign + +export const CampaignModelResponseTransformer: CampaignModelResponseTransformer = + (data) => { + if (data?.start_date) { + data.start_date = new Date(data.start_date) + } + return data + } + +export const ListCampaignsResponseTransformer: ListCampaignsResponseTransformer = + async (data) => { + if (Array.isArray(data?.results)) { + data.results.forEach(CampaignModelResponseTransformer) + } + return data + } + +export type RetrieveCampaignResponseTransformer = ( + data: any +) => Promise + +export const RetrieveCampaignResponseTransformer: RetrieveCampaignResponseTransformer = + async (data) => { + CampaignModelResponseTransformer(data) + return data + } + +export type PublishFoiMessageDraftResponseTransformer = ( + data: any +) => Promise + +export const PublishFoiMessageDraftResponseTransformer: PublishFoiMessageDraftResponseTransformer = + async (data) => { + FoiMessageDraftModelResponseTransformer(data) + return data + } + +export type ClaimProblemReportResponseTransformer = ( + data: any +) => Promise + +export const ClaimProblemReportResponseTransformer: ClaimProblemReportResponseTransformer = + async (data) => { + ProblemReportModelResponseTransformer(data) + return data + } + +export type EscalateProblemReportResponseTransformer = ( + data: any +) => Promise + +export const EscalateProblemReportResponseTransformer: EscalateProblemReportResponseTransformer = + async (data) => { + ProblemReportModelResponseTransformer(data) + return data + } + +export type ResolveProblemReportResponseTransformer = ( + data: any +) => Promise + +export const ResolveProblemReportResponseTransformer: ResolveProblemReportResponseTransformer = + async (data) => { + ProblemReportModelResponseTransformer(data) + return data + } + +export type UnclaimProblemReportResponseTransformer = ( + data: any +) => Promise + +export const UnclaimProblemReportResponseTransformer: UnclaimProblemReportResponseTransformer = + async (data) => { + ProblemReportModelResponseTransformer(data) + return data + } + +export type CreateUploadCreateResponseTransformer = ( + data: any +) => Promise + +export type UploadCreateModelResponseTransformer = (data: any) => UploadCreate + +export const UploadCreateModelResponseTransformer: UploadCreateModelResponseTransformer = + (data) => { + if (data?.expires) { + data.expires = new Date(data.expires) + } + return data + } + +export const CreateUploadCreateResponseTransformer: CreateUploadCreateResponseTransformer = + async (data) => { + UploadCreateModelResponseTransformer(data) + return data + } + +export type UpdateUploadResponseTransformer = ( + data: any +) => Promise + +export type UploadModelResponseTransformer = (data: any) => Upload + +export const UploadModelResponseTransformer: UploadModelResponseTransformer = ( + data +) => { + if (data?.expires) { + data.expires = new Date(data.expires) + } + return data +} + +export const UpdateUploadResponseTransformer: UpdateUploadResponseTransformer = + async (data) => { + UploadModelResponseTransformer(data) + return data + } + +export type PartialUpdateUploadResponseTransformer = ( + data: any +) => Promise + +export const PartialUpdateUploadResponseTransformer: PartialUpdateUploadResponseTransformer = + async (data) => { + UploadModelResponseTransformer(data) + return data + } diff --git a/frontend/javascript/api/index.ts b/frontend/javascript/api/index.ts new file mode 100644 index 000000000..03b0705e7 --- /dev/null +++ b/frontend/javascript/api/index.ts @@ -0,0 +1,12 @@ +import { client } from './gen/services.gen' + +const token = document.cookie.match(/csrftoken=([^;]+)/)?.[1] + +client.interceptors.request.use((request) => { + request.headers.set('X-CSRFToken', token!) + return request +}) + +export * from './gen/schemas.gen' +export * from './gen/services.gen' +export * from './gen/types.gen' diff --git a/openapi-ts.config.ts b/openapi-ts.config.ts new file mode 100644 index 000000000..52fb530d5 --- /dev/null +++ b/openapi-ts.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from '@hey-api/openapi-ts' + +export default defineConfig({ + client: '@hey-api/client-fetch', + input: 'froide/openapi-schema.yaml', + output: { + path: 'frontend/javascript/api/gen', + format: 'prettier', + lint: 'eslint' + }, + plugins: [ + '@hey-api/schemas', + '@hey-api/services', + { + dates: true, + name: '@hey-api/transformers' + }, + { + enums: 'javascript', + name: '@hey-api/types' + } + ] +}) diff --git a/package.json b/package.json index 93d3ad5d3..5f5998099 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "serve": "vite", "dev": "vite", "build": "vite build", + "openapi": "openapi-ts", "favicon": "real-favicon generate froide/static/img/logo/favicon.json favicon-result.json froide/static/img/logo" }, "repository": { @@ -43,6 +44,8 @@ "vite-plugin-dev-manifest": "^1.0.9" }, "dependencies": { + "@hey-api/client-fetch": "^0.4.3", + "@hey-api/openapi-ts": "^0.55.2", "@okfde/filingcabinet": "github:okfde/django-filingcabinet", "@popperjs/core": "^2.11.5", "@types/lodash.throttle": "^4.1.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1d9c08a0..315a0e4d1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,12 @@ importers: .: dependencies: + '@hey-api/client-fetch': + specifier: ^0.4.3 + version: 0.4.3 + '@hey-api/openapi-ts': + specifier: ^0.55.2 + version: 0.55.2(typescript@5.2.2) '@okfde/filingcabinet': specifier: github:okfde/django-filingcabinet version: https://codeload.github.com/okfde/django-filingcabinet/tar.gz/69cde01cf767ebf6447d057b1400b87c32d03803(worker-loader@3.0.8(webpack@5.94.0)) @@ -86,7 +92,7 @@ importers: devDependencies: '@okfde/eslint-config-froide': specifier: okfde/eslint-config-froide - version: https://codeload.github.com/okfde/eslint-config-froide/tar.gz/daabc1889e3b91e8c09eed6326ce4788a8cd116c(typescript@5.2.2) + version: https://codeload.github.com/okfde/eslint-config-froide/tar.gz/daabc1889e3b91e8c09eed6326ce4788a8cd116c(jiti@2.4.0)(typescript@5.2.2) '@types/bootstrap': specifier: ^5.2.1 version: 5.2.7 @@ -120,6 +126,10 @@ importers: packages: + '@apidevtools/json-schema-ref-parser@11.7.2': + resolution: {integrity: sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==} + engines: {node: '>= 16'} + '@babel/helper-string-parser@7.24.8': resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} @@ -299,6 +309,16 @@ packages: resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@hey-api/client-fetch@0.4.3': + resolution: {integrity: sha512-Y0McgfJED/Iq6Tr8LgewFL+qrOpb87rUBUJkc6mLzxqTkqF52KcexYZPlKyjee0Qb/oUJOupFRpvUEWjH/339w==} + + '@hey-api/openapi-ts@0.55.2': + resolution: {integrity: sha512-EdVslFxtV27prj8oLWCm4ZOFAx+zGOqRVbDkKOcaYzg6wQQdvQ0j14LMapvhM0PtP2hkffh6PGeh6dt9aJORZQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + typescript: ^5.x + '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} @@ -331,6 +351,9 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -748,6 +771,14 @@ packages: resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} engines: {node: '>=0.2.0'} + c12@2.0.1: + resolution: {integrity: sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} @@ -779,10 +810,21 @@ packages: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + classnames@2.3.2: resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} @@ -800,12 +842,23 @@ packages: combine-errors@3.0.3: resolution: {integrity: sha512-C8ikRNRMygCwaTx+Ek3Yr+OuZzgZjduCOfSQBjbM8V3MfgcjSTeto/GXP6PAwKvJz/v15b7GHZvx5rOlczFw/Q==} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -854,6 +907,12 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + destr@2.0.3: + resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + dom-serializer@0.1.1: resolution: {integrity: sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==} @@ -875,6 +934,10 @@ packages: domutils@1.7.0: resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + driver.js@1.3.1: resolution: {integrity: sha512-MvUdXbqSgEsgS/H9KyWb5Rxy0aE6BhOVT4cssi2x2XjmXea6qQfgdx32XKVLLSqTaIw7q/uxU5Xl3NV7+cN6FQ==} @@ -1010,6 +1073,10 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + exifr@7.1.3: resolution: {integrity: sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==} @@ -1070,6 +1137,10 @@ packages: fraction.js@4.3.6: resolution: {integrity: sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==} + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1100,10 +1171,18 @@ packages: get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} + giget@1.2.3: + resolution: {integrity: sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==} + hasBin: true + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1144,6 +1223,11 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -1173,6 +1257,10 @@ packages: htmlparser2@3.10.1: resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1262,6 +1350,10 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} @@ -1290,6 +1382,10 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} + jiti@2.4.0: + resolution: {integrity: sha512-H5UpaUI+aHOqZXlYOaFP/8AzKsg+guWu+Pr3Y8i7+Y3zr1aXAvCvTAQ1RxSc6oVD8R8c7brgNtTVP91E7upH/g==} + hasBin: true + js-base64@3.7.5: resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==} @@ -1446,6 +1542,10 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1456,6 +1556,18 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + mitt@2.1.0: resolution: {integrity: sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==} @@ -1463,11 +1575,19 @@ packages: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + mkdirp@3.0.1: resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} engines: {node: '>=10'} hasBin: true + mlly@1.7.2: + resolution: {integrity: sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1490,6 +1610,9 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + node-fetch-native@1.6.4: + resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} @@ -1507,12 +1630,21 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + nth-check@1.0.2: resolution: {integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==} nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nypm@0.3.12: + resolution: {integrity: sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} @@ -1524,9 +1656,16 @@ packages: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} engines: {node: '>= 0.4'} + ohash@1.1.4: + resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1566,11 +1705,21 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pdfjs-dist@2.9.359: resolution: {integrity: sha512-P2nYtkacdlZaNNwrBLw1ZyMm0oE2yY/5S/GDCAmMJ7U4+ciL/D0mrlEC/o4HZZc/LNE3w8lEVzBEyVgEQlPVKQ==} peerDependencies: worker-loader: ^3.0.7 + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -1581,6 +1730,9 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + pkg-types@1.2.1: + resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} + postcss-selector-parser@6.1.2: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} @@ -1628,6 +1780,9 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + readable-stream@1.0.34: resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} @@ -1639,6 +1794,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} + redux@4.2.1: resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} @@ -1729,6 +1888,10 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + slice-stream@1.0.0: resolution: {integrity: sha512-fJu1TYTr85OZEkT4lqcCW6oPWPIS5omPnIsB/dL7QWo2sNk03VQ6did4plhh0y3Sf0nJlq5QEUR3vMYevydn7w==} @@ -1772,6 +1935,10 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -1788,6 +1955,10 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + terser-webpack-plugin@5.3.10: resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} @@ -1869,6 +2040,14 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + hasBin: true + unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -2012,6 +2191,9 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + worker-loader@3.0.8: resolution: {integrity: sha512-XQyQkIFeRVC7f7uRhFdNMe/iJOdO6zxAaR3EWbDp45v3mDhrTi+++oswKNxShUNjPC/1xUp5DB29YKLhFo129g==} engines: {node: '>= 10.13.0'} @@ -2025,12 +2207,21 @@ packages: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} snapshots: + '@apidevtools/json-schema-ref-parser@11.7.2': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.0 + '@babel/helper-string-parser@7.24.8': {} '@babel/helper-validator-identifier@7.24.7': {} @@ -2115,9 +2306,9 @@ snapshots: '@esbuild/win32-x64@0.18.20': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.9.1)': + '@eslint-community/eslint-utils@4.4.0(eslint@9.9.1(jiti@2.4.0))': dependencies: - eslint: 9.9.1 + eslint: 9.9.1(jiti@2.4.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.11.0': {} @@ -2148,6 +2339,18 @@ snapshots: '@eslint/object-schema@2.1.4': {} + '@hey-api/client-fetch@0.4.3': {} + + '@hey-api/openapi-ts@0.55.2(typescript@5.2.2)': + dependencies: + '@apidevtools/json-schema-ref-parser': 11.7.2 + c12: 2.0.1 + commander: 12.1.0 + handlebars: 4.7.8 + typescript: 5.2.2 + transitivePeerDependencies: + - magicast + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.3.0': {} @@ -2176,6 +2379,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@jsdevtools/ono@7.1.3': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2188,14 +2393,14 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@okfde/eslint-config-froide@https://codeload.github.com/okfde/eslint-config-froide/tar.gz/daabc1889e3b91e8c09eed6326ce4788a8cd116c(typescript@5.2.2)': + '@okfde/eslint-config-froide@https://codeload.github.com/okfde/eslint-config-froide/tar.gz/daabc1889e3b91e8c09eed6326ce4788a8cd116c(jiti@2.4.0)(typescript@5.2.2)': dependencies: - eslint: 9.9.1 - eslint-config-prettier: 9.1.0(eslint@9.9.1) - eslint-plugin-vue: 9.28.0(eslint@9.9.1) + eslint: 9.9.1(jiti@2.4.0) + eslint-config-prettier: 9.1.0(eslint@9.9.1(jiti@2.4.0)) + eslint-plugin-vue: 9.28.0(eslint@9.9.1(jiti@2.4.0)) prettier: 3.3.3 prettier-config-standard: 7.0.0(prettier@3.3.3) - typescript-eslint: 8.4.0(eslint@9.9.1)(typescript@5.2.2) + typescript-eslint: 8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2) transitivePeerDependencies: - jiti - supports-color @@ -2241,15 +2446,15 @@ snapshots: '@types/web-bluetooth@0.0.20': {} - '@typescript-eslint/eslint-plugin@8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.1)(typescript@5.2.2))(eslint@9.9.1)(typescript@5.2.2)': + '@typescript-eslint/eslint-plugin@8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2))(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 8.4.0(eslint@9.9.1)(typescript@5.2.2) + '@typescript-eslint/parser': 8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2) '@typescript-eslint/scope-manager': 8.4.0 - '@typescript-eslint/type-utils': 8.4.0(eslint@9.9.1)(typescript@5.2.2) - '@typescript-eslint/utils': 8.4.0(eslint@9.9.1)(typescript@5.2.2) + '@typescript-eslint/type-utils': 8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2) + '@typescript-eslint/utils': 8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2) '@typescript-eslint/visitor-keys': 8.4.0 - eslint: 9.9.1 + eslint: 9.9.1(jiti@2.4.0) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -2259,14 +2464,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.4.0(eslint@9.9.1)(typescript@5.2.2)': + '@typescript-eslint/parser@8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2)': dependencies: '@typescript-eslint/scope-manager': 8.4.0 '@typescript-eslint/types': 8.4.0 '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.2.2) '@typescript-eslint/visitor-keys': 8.4.0 debug: 4.3.7 - eslint: 9.9.1 + eslint: 9.9.1(jiti@2.4.0) optionalDependencies: typescript: 5.2.2 transitivePeerDependencies: @@ -2277,10 +2482,10 @@ snapshots: '@typescript-eslint/types': 8.4.0 '@typescript-eslint/visitor-keys': 8.4.0 - '@typescript-eslint/type-utils@8.4.0(eslint@9.9.1)(typescript@5.2.2)': + '@typescript-eslint/type-utils@8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2)': dependencies: '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.2.2) - '@typescript-eslint/utils': 8.4.0(eslint@9.9.1)(typescript@5.2.2) + '@typescript-eslint/utils': 8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2) debug: 4.3.7 ts-api-utils: 1.3.0(typescript@5.2.2) optionalDependencies: @@ -2306,13 +2511,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.4.0(eslint@9.9.1)(typescript@5.2.2)': + '@typescript-eslint/utils@8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1(jiti@2.4.0)) '@typescript-eslint/scope-manager': 8.4.0 '@typescript-eslint/types': 8.4.0 '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.2.2) - eslint: 9.9.1 + eslint: 9.9.1(jiti@2.4.0) transitivePeerDependencies: - supports-color - typescript @@ -2700,6 +2905,21 @@ snapshots: buffers@0.1.1: {} + c12@2.0.1: + dependencies: + chokidar: 4.0.1 + confbox: 0.1.8 + defu: 6.1.4 + dotenv: 16.4.5 + giget: 1.2.3 + jiti: 2.4.0 + mlly: 1.7.2 + ohash: 1.1.4 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + pkg-types: 1.2.1 + rc9: 2.1.2 + call-bind@1.0.2: dependencies: function-bind: 1.1.1 @@ -2757,8 +2977,18 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.1: + dependencies: + readdirp: 4.0.2 + + chownr@2.0.0: {} + chrome-trace-event@1.0.4: {} + citty@0.1.6: + dependencies: + consola: 3.2.3 + classnames@2.3.2: {} cli-real-favicon@0.0.8: @@ -2781,10 +3011,16 @@ snapshots: custom-error-instance: 2.1.1 lodash.uniqby: 4.5.0 + commander@12.1.0: {} + commander@2.20.3: {} concat-map@0.0.1: {} + confbox@0.1.8: {} + + consola@3.2.3: {} + core-util-is@1.0.3: {} cross-spawn@7.0.3: @@ -2828,6 +3064,10 @@ snapshots: has-property-descriptors: 1.0.0 object-keys: 1.1.1 + defu@6.1.4: {} + + destr@2.0.3: {} + dom-serializer@0.1.1: dependencies: domelementtype: 1.3.1 @@ -2856,6 +3096,8 @@ snapshots: dom-serializer: 0.2.2 domelementtype: 1.3.1 + dotenv@16.4.5: {} + driver.js@1.3.1: {} electron-to-chromium@1.4.528: {} @@ -2960,20 +3202,20 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@9.1.0(eslint@9.9.1): + eslint-config-prettier@9.1.0(eslint@9.9.1(jiti@2.4.0)): dependencies: - eslint: 9.9.1 + eslint: 9.9.1(jiti@2.4.0) - eslint-plugin-vue@9.28.0(eslint@9.9.1): + eslint-plugin-vue@9.28.0(eslint@9.9.1(jiti@2.4.0)): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) - eslint: 9.9.1 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1(jiti@2.4.0)) + eslint: 9.9.1(jiti@2.4.0) globals: 13.24.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.1.2 semver: 7.6.3 - vue-eslint-parser: 9.4.3(eslint@9.9.1) + vue-eslint-parser: 9.4.3(eslint@9.9.1(jiti@2.4.0)) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -2997,9 +3239,9 @@ snapshots: eslint-visitor-keys@4.0.0: {} - eslint@9.9.1: + eslint@9.9.1(jiti@2.4.0): dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1(jiti@2.4.0)) '@eslint-community/regexpp': 4.11.0 '@eslint/config-array': 0.18.0 '@eslint/eslintrc': 3.1.0 @@ -3033,6 +3275,8 @@ snapshots: optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 + optionalDependencies: + jiti: 2.4.0 transitivePeerDependencies: - supports-color @@ -3068,6 +3312,18 @@ snapshots: events@3.3.0: {} + execa@8.0.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + exifr@7.1.3: {} exifreader@4.13.0: @@ -3122,6 +3378,10 @@ snapshots: fraction.js@4.3.6: {} + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -3154,11 +3414,24 @@ snapshots: has-proto: 1.0.1 has-symbols: 1.0.3 + get-stream@8.0.1: {} + get-symbol-description@1.0.0: dependencies: call-bind: 1.0.2 get-intrinsic: 1.2.1 + giget@1.2.3: + dependencies: + citty: 0.1.6 + consola: 3.2.3 + defu: 6.1.4 + node-fetch-native: 1.6.4 + nypm: 0.3.12 + ohash: 1.1.4 + pathe: 1.1.2 + tar: 6.2.1 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -3204,6 +3477,15 @@ snapshots: graphemer@1.4.0: {} + handlebars@4.7.8: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + has-bigints@1.0.2: {} has-flag@4.0.0: {} @@ -3233,6 +3515,8 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + human-signals@5.0.0: {} + ignore@5.3.2: {} immutable@4.3.4: {} @@ -3313,6 +3597,8 @@ snapshots: is-stream@2.0.1: {} + is-stream@3.0.0: {} + is-string@1.0.7: dependencies: has-tostringtag: 1.0.0 @@ -3341,6 +3627,8 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jiti@2.4.0: {} + js-base64@3.7.5: {} js-yaml@4.1.0: @@ -3477,6 +3765,8 @@ snapshots: dependencies: mime-db: 1.52.0 + mimic-fn@4.0.0: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -3487,14 +3777,34 @@ snapshots: minimist@1.2.8: {} + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + mitt@2.1.0: {} mkdirp@0.5.6: dependencies: minimist: 1.2.8 + mkdirp@1.0.4: {} + mkdirp@3.0.1: {} + mlly@1.7.2: + dependencies: + acorn: 8.14.0 + pathe: 1.1.2 + pkg-types: 1.2.1 + ufo: 1.5.4 + ms@2.1.3: {} namespace-emitter@2.0.1: {} @@ -3507,6 +3817,8 @@ snapshots: neo-async@2.6.2: {} + node-fetch-native@1.6.4: {} + node-releases@2.0.13: {} node-releases@2.0.18: {} @@ -3524,6 +3836,10 @@ snapshots: normalize-range@0.1.2: {} + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + nth-check@1.0.2: dependencies: boolbase: 1.0.0 @@ -3532,6 +3848,15 @@ snapshots: dependencies: boolbase: 1.0.0 + nypm@0.3.12: + dependencies: + citty: 0.1.6 + consola: 3.2.3 + execa: 8.0.1 + pathe: 1.1.2 + pkg-types: 1.2.1 + ufo: 1.5.4 + object-inspect@1.12.3: {} object-keys@1.1.1: {} @@ -3543,10 +3868,16 @@ snapshots: has-symbols: 1.0.3 object-keys: 1.1.1 + ohash@1.1.4: {} + once@1.4.0: dependencies: wrappy: 1.0.2 + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3583,16 +3914,28 @@ snapshots: path-key@3.1.1: {} + path-key@4.0.0: {} + + pathe@1.1.2: {} + pdfjs-dist@2.9.359(worker-loader@3.0.8(webpack@5.94.0)): dependencies: worker-loader: 3.0.8(webpack@5.94.0) + perfect-debounce@1.0.0: {} + picocolors@1.0.0: {} picocolors@1.1.1: {} picomatch@2.3.1: {} + pkg-types@1.2.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.2 + pathe: 1.1.2 + postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 @@ -3639,6 +3982,11 @@ snapshots: dependencies: safe-buffer: 5.2.1 + rc9@2.1.2: + dependencies: + defu: 6.1.4 + destr: 2.0.3 + readable-stream@1.0.34: dependencies: core-util-is: 1.0.3 @@ -3656,6 +4004,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.0.2: {} + redux@4.2.1: dependencies: '@babel/runtime': 7.22.6 @@ -3753,6 +4103,8 @@ snapshots: signal-exit@3.0.7: {} + signal-exit@4.1.0: {} + slice-stream@1.0.0: dependencies: readable-stream: 1.0.34 @@ -3803,6 +4155,8 @@ snapshots: dependencies: ansi-regex: 5.0.1 + strip-final-newline@3.0.0: {} + strip-json-comments@3.1.1: {} supports-color@7.2.0: @@ -3815,6 +4169,15 @@ snapshots: tapable@2.2.1: {} + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + terser-webpack-plugin@5.3.10(webpack@5.94.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -3888,11 +4251,11 @@ snapshots: for-each: 0.3.3 is-typed-array: 1.1.12 - typescript-eslint@8.4.0(eslint@9.9.1)(typescript@5.2.2): + typescript-eslint@8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.1)(typescript@5.2.2))(eslint@9.9.1)(typescript@5.2.2) - '@typescript-eslint/parser': 8.4.0(eslint@9.9.1)(typescript@5.2.2) - '@typescript-eslint/utils': 8.4.0(eslint@9.9.1)(typescript@5.2.2) + '@typescript-eslint/eslint-plugin': 8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2))(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2) + '@typescript-eslint/parser': 8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2) + '@typescript-eslint/utils': 8.4.0(eslint@9.9.1(jiti@2.4.0))(typescript@5.2.2) optionalDependencies: typescript: 5.2.2 transitivePeerDependencies: @@ -3901,6 +4264,11 @@ snapshots: typescript@5.2.2: {} + ufo@1.5.4: {} + + uglify-js@3.19.3: + optional: true + unbox-primitive@1.0.2: dependencies: call-bind: 1.0.2 @@ -3954,10 +4322,10 @@ snapshots: dependencies: vue: 3.3.4 - vue-eslint-parser@9.4.3(eslint@9.9.1): + vue-eslint-parser@9.4.3(eslint@9.9.1(jiti@2.4.0)): dependencies: debug: 4.3.7 - eslint: 9.9.1 + eslint: 9.9.1(jiti@2.4.0) eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 @@ -4060,6 +4428,8 @@ snapshots: word-wrap@1.2.5: {} + wordwrap@1.0.0: {} + worker-loader@3.0.8(webpack@5.94.0): dependencies: loader-utils: 2.0.4 @@ -4070,4 +4440,6 @@ snapshots: xml-name-validator@4.0.0: {} + yallist@4.0.0: {} + yocto-queue@0.1.0: {} diff --git a/tsconfig.json b/tsconfig.json index 9cc3c208d..bcd60ba61 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,7 @@ }, "include": [ "./frontend/**/*", - "vite.config.js" + "vite.config.js", + "openapi-ts.config.ts" ] } \ No newline at end of file