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