Skip to content

Commit 96d0825

Browse files
committed
2 parents c76d79a + 3d12717 commit 96d0825

File tree

18 files changed

+207
-81
lines changed

18 files changed

+207
-81
lines changed

label_studio/core/settings/base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,3 +867,7 @@ def collect_versions_dummy(**kwargs):
867867
USER_ACTIVITY_BATCH_SIZE = int(get_env('USER_ACTIVITY_BATCH_SIZE', '100'))
868868
USER_ACTIVITY_SYNC_THRESHOLD = int(get_env('USER_ACTIVITY_SYNC_THRESHOLD', '500'))
869869
USER_ACTIVITY_REDIS_TTL = int(get_env('USER_ACTIVITY_REDIS_TTL', '86400')) # 24 hours
870+
871+
# Data Manager
872+
# Max number of users to display in the Data Manager in Annotators/Reviewers/Comment Authors, etc
873+
DM_MAX_USERS_TO_DISPLAY = int(get_env('DM_MAX_USERS_TO_DISPLAY', 10))

label_studio/data_export/api.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ def get(self, request, *args, **kwargs):
8585
@method_decorator(
8686
name='get',
8787
decorator=extend_schema(
88-
deprecated=True,
8988
parameters=[
9089
OpenApiParameter(
9190
name='export_type',
@@ -95,7 +94,7 @@ def get(self, request, *args, **kwargs):
9594
),
9695
OpenApiParameter(
9796
name='download_all_tasks',
98-
type=OpenApiTypes.STR,
97+
type=OpenApiTypes.BOOL,
9998
location='query',
10099
description='If true, download all tasks regardless of status. If false, download only annotated tasks.',
101100
),
@@ -154,8 +153,8 @@ def get(self, request, *args, **kwargs):
154153
)
155154
},
156155
extensions={
157-
'x-fern-sdk-group-name': 'projects',
158-
'x-fern-sdk-method-name': 'export',
156+
'x-fern-sdk-group-name': ['projects', 'exports'],
157+
'x-fern-sdk-method-name': 'download_sync',
159158
'x-fern-audiences': ['public'],
160159
},
161160
),
@@ -375,7 +374,7 @@ def filter_queryset(self, queryset):
375374
),
376375
OpenApiParameter(
377376
name='export_pk',
378-
type=OpenApiTypes.STR,
377+
type=OpenApiTypes.INT,
379378
location='path',
380379
description='Primary key identifying the export file.',
381380
),
@@ -402,7 +401,7 @@ def filter_queryset(self, queryset):
402401
),
403402
OpenApiParameter(
404403
name='export_pk',
405-
type=OpenApiTypes.STR,
404+
type=OpenApiTypes.INT,
406405
location='path',
407406
description='Primary key identifying the export file.',
408407
),
@@ -482,11 +481,20 @@ def get_queryset(self):
482481
),
483482
OpenApiParameter(
484483
name='export_pk',
485-
type=OpenApiTypes.STR,
484+
type=OpenApiTypes.INT,
486485
location='path',
487486
description='Primary key identifying the export file.',
488487
),
489488
],
489+
responses={
490+
(200, 'application/*'): OpenApiResponse(
491+
description='Export file',
492+
response={
493+
'type': 'string',
494+
'format': 'binary',
495+
},
496+
),
497+
},
490498
extensions={
491499
'x-fern-sdk-group-name': ['projects', 'exports'],
492500
'x-fern-sdk-method-name': 'download',
@@ -628,11 +636,22 @@ def set_convert_background_failure(job, connection, type, value, traceback_obj):
628636
),
629637
OpenApiParameter(
630638
name='export_pk',
631-
type=OpenApiTypes.STR,
639+
type=OpenApiTypes.INT,
632640
location='path',
633641
description='Primary key identifying the export file.',
634642
),
635643
],
644+
responses={
645+
200: OpenApiResponse(
646+
response={
647+
'type': 'object',
648+
'properties': {
649+
'export_type': {'type': 'string'},
650+
'converted_format': {'type': 'integer'},
651+
},
652+
},
653+
),
654+
},
636655
extensions={
637656
'x-fern-sdk-group-name': ['projects', 'exports'],
638657
'x-fern-sdk-method-name': 'convert',

label_studio/data_import/api.py

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -220,29 +220,7 @@
220220
""".format(
221221
host=(settings.HOSTNAME or 'https://localhost:8080')
222222
),
223-
request={
224-
'type': 'array',
225-
'items': {'type': 'object'},
226-
# TODO: this example doesn't work - perhaps we need to migrate to drf-spectacular for "anyOf" support
227-
# also fern will change to at least provide a list of examples FER-1969
228-
# right now we can only rely on documenation examples
229-
# properties={
230-
# 'data': openapi.Schema(type=OpenApiTypes.OBJECT, description='Data of the task'),
231-
# 'annotations': openapi.Schema(
232-
# many=True,
233-
# description='Annotations for this task',
234-
# ),
235-
# 'predictions': openapi.Schema(
236-
# many=True,
237-
# description='Predictions for this task',
238-
# )
239-
# },
240-
# example={
241-
# 'data': {'image': 'http://example.com/image.jpg'},
242-
# 'annotations': [annotation_response_example],
243-
# 'predictions': [prediction_response_example]
244-
# }
245-
},
223+
request=ImportApiSerializer(many=True),
246224
extensions={
247225
'x-fern-sdk-group-name': 'projects',
248226
'x-fern-sdk-method-name': 'import_tasks',
@@ -582,7 +560,7 @@ def post(self, *args, **kwargs):
582560
Retrieve the list of uploaded files used to create labeling tasks for a specific project.
583561
""",
584562
extensions={
585-
'x-fern-sdk-group-name': ['projects', 'file_uploads'],
563+
'x-fern-sdk-group-name': ['files'],
586564
'x-fern-sdk-method-name': 'list',
587565
'x-fern-audiences': ['public'],
588566
},
@@ -597,7 +575,7 @@ def post(self, *args, **kwargs):
597575
Delete uploaded files for a specific project.
598576
""",
599577
extensions={
600-
'x-fern-sdk-group-name': ['projects', 'file_uploads'],
578+
'x-fern-sdk-group-name': ['files'],
601579
'x-fern-sdk-method-name': 'delete_many',
602580
'x-fern-audiences': ['public'],
603581
},
@@ -646,7 +624,7 @@ def delete(self, request, *args, **kwargs):
646624
summary='Get file upload',
647625
description='Retrieve details about a specific uploaded file.',
648626
extensions={
649-
'x-fern-sdk-group-name': ['projects', 'file_uploads'],
627+
'x-fern-sdk-group-name': ['files'],
650628
'x-fern-sdk-method-name': 'get',
651629
'x-fern-audiences': ['public'],
652630
},
@@ -660,7 +638,7 @@ def delete(self, request, *args, **kwargs):
660638
description='Update a specific uploaded file.',
661639
request=FileUploadSerializer,
662640
extensions={
663-
'x-fern-sdk-group-name': ['projects', 'file_uploads'],
641+
'x-fern-sdk-group-name': ['files'],
664642
'x-fern-sdk-method-name': 'update',
665643
'x-fern-audiences': ['public'],
666644
},
@@ -673,7 +651,7 @@ def delete(self, request, *args, **kwargs):
673651
summary='Delete file upload',
674652
description='Delete a specific uploaded file.',
675653
extensions={
676-
'x-fern-sdk-group-name': ['projects', 'file_uploads'],
654+
'x-fern-sdk-group-name': ['files'],
677655
'x-fern-sdk-method-name': 'delete',
678656
'x-fern-audiences': ['public'],
679657
},
@@ -706,7 +684,7 @@ def put(self, *args, **kwargs):
706684
summary='Download file',
707685
description='Download a specific uploaded file.',
708686
extensions={
709-
'x-fern-sdk-group-name': ['projects', 'file_uploads'],
687+
'x-fern-sdk-group-name': ['files'],
710688
'x-fern-sdk-method-name': 'download',
711689
'x-fern-audiences': ['public'],
712690
},

label_studio/data_manager/api.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,30 @@ def paginate_queryset(self, queryset, request, view=None):
259259
return self.paginate_totals_queryset(queryset, request, view)
260260
return self.sync_paginate_queryset(queryset, request, view)
261261

262+
def get_paginated_response_schema(self, schema):
263+
return {
264+
'type': 'object',
265+
'properties': {
266+
'tasks': schema,
267+
'total': {
268+
'type': 'integer',
269+
'description': 'Total number of tasks',
270+
'example': 123,
271+
},
272+
'total_annotations': {
273+
'type': 'integer',
274+
'description': 'Total number of annotations',
275+
'example': 456,
276+
},
277+
'total_predictions': {
278+
'type': 'integer',
279+
'description': 'Total number of predictions',
280+
'example': 78,
281+
},
282+
},
283+
'required': ['tasks', 'total', 'total_annotations', 'total_predictions'],
284+
}
285+
262286
def get_paginated_response(self, data):
263287
return Response(
264288
{

label_studio/jwt_auth/auth.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,9 @@ def get_security_definition(self, auto_schema):
5050
'<br><pre><code class="language-bash">'
5151
'curl https://label-studio-host/api/projects -H "Authorization: Token [your-token]"'
5252
'</code></pre>',
53+
'x-fern-header': {
54+
'name': 'api_key',
55+
'env': 'LABEL_STUDIO_API_KEY',
56+
'prefix': 'Token ',
57+
},
5358
}

label_studio/jwt_auth/views.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ class TokenExistsError(APIException):
3939
tags=['JWT'],
4040
summary='Retrieve JWT Settings',
4141
description='Retrieve JWT settings for the currently active organization.',
42+
extensions={
43+
'x-fern-sdk-group-name': 'jwt_settings',
44+
'x-fern-sdk-method-name': 'get',
45+
'x-fern-audiences': ['public'],
46+
},
4247
),
4348
)
4449
@method_decorator(
@@ -47,6 +52,11 @@ class TokenExistsError(APIException):
4752
tags=['JWT'],
4853
summary='Update JWT Settings',
4954
description='Update JWT settings for the currently active organization.',
55+
extensions={
56+
'x-fern-sdk-group-name': 'jwt_settings',
57+
'x-fern-sdk-method-name': 'update',
58+
'x-fern-audiences': ['public'],
59+
},
5060
),
5161
)
5262
class JWTSettingsAPI(CreateAPIView):
@@ -76,14 +86,19 @@ def post(self, request, *args, **kwargs):
7686
return Response(serializer.data)
7787

7888

79-
# Recommended implementation from JWT to support drf-yasg:
80-
# https://django-rest-framework-simplejwt.readthedocs.io/en/latest/drf_yasg_integration.html
8189
class DecoratedTokenRefreshView(TokenRefreshView):
8290
@extend_schema(
8391
tags=['JWT'],
92+
summary='Refresh JWT token',
93+
description='Get a new access token, using a refresh token.',
8494
responses={
8595
status.HTTP_200_OK: TokenRefreshResponseSerializer,
8696
},
97+
extensions={
98+
'x-fern-sdk-group-name': 'tokens',
99+
'x-fern-sdk-method-name': 'refresh',
100+
'x-fern-audiences': ['public'],
101+
},
87102
)
88103
def post(self, request, *args, **kwargs):
89104
return super().post(request, *args, **kwargs)
@@ -95,6 +110,14 @@ def post(self, request, *args, **kwargs):
95110
tags=['JWT'],
96111
summary='List API tokens',
97112
description='List all API tokens for the current user.',
113+
responses={
114+
status.HTTP_200_OK: LSAPITokenListSerializer,
115+
},
116+
extensions={
117+
'x-fern-sdk-group-name': 'tokens',
118+
'x-fern-sdk-method-name': 'list',
119+
'x-fern-audiences': ['public'],
120+
},
98121
),
99122
)
100123
@method_decorator(
@@ -103,6 +126,14 @@ def post(self, request, *args, **kwargs):
103126
tags=['JWT'],
104127
summary='Create API token',
105128
description='Create a new API token for the current user.',
129+
responses={
130+
status.HTTP_201_CREATED: LSAPITokenCreateSerializer,
131+
},
132+
extensions={
133+
'x-fern-sdk-group-name': 'tokens',
134+
'x-fern-sdk-method-name': 'create',
135+
'x-fern-audiences': ['public'],
136+
},
106137
),
107138
)
108139
class LSAPITokenView(generics.ListCreateAPIView):
@@ -172,6 +203,11 @@ class LSTokenBlacklistView(TokenViewBase):
172203
status.HTTP_204_NO_CONTENT: 'Token was successfully blacklisted',
173204
status.HTTP_404_NOT_FOUND: 'Token is already blacklisted',
174205
},
206+
extensions={
207+
'x-fern-sdk-group-name': 'tokens',
208+
'x-fern-sdk-method-name': 'blacklist',
209+
'x-fern-audiences': ['public'],
210+
},
175211
)
176212
def post(self, request, *args, **kwargs):
177213
serializer = self.get_serializer(data=request.data)
@@ -202,6 +238,11 @@ class LSAPITokenRotateView(TokenViewBase):
202238
status.HTTP_200_OK: TokenRotateResponseSerializer,
203239
status.HTTP_400_BAD_REQUEST: 'Invalid token or token already blacklisted',
204240
},
241+
extensions={
242+
'x-fern-sdk-group-name': 'tokens',
243+
'x-fern-sdk-method-name': 'rotate',
244+
'x-fern-audiences': ['public'],
245+
},
205246
)
206247
def post(self, request, *args, **kwargs):
207248
serializer = self.get_serializer(data=request.data)

label_studio/ml/api.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,25 @@ def post(self, request, *args, **kwargs):
440440
tags=['Machine Learning'],
441441
summary='Get model versions',
442442
description='Get available versions of the model.',
443-
responses={'200': 'List of available versions.'},
443+
responses={
444+
200: OpenApiResponse(
445+
description='List of available versions.',
446+
response={
447+
'type': 'object',
448+
'properties': {
449+
'versions': {
450+
'type': 'array',
451+
'items': {
452+
'type': 'string',
453+
},
454+
},
455+
'message': {
456+
'type': 'string',
457+
},
458+
},
459+
},
460+
),
461+
},
444462
extensions={
445463
'x-fern-sdk-group-name': 'ml',
446464
'x-fern-sdk-method-name': 'list_model_versions',
@@ -449,7 +467,7 @@ def post(self, request, *args, **kwargs):
449467
),
450468
)
451469
class MLBackendVersionsAPI(generics.RetrieveAPIView):
452-
470+
# TODO(jo): implement this view with a serializer and replace the handwritten schema above with it
453471
permission_required = all_permissions.projects_change
454472

455473
def get(self, request, *args, **kwargs):

label_studio/organizations/api.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from django.urls import reverse
1010
from django.utils.decorators import method_decorator
1111
from drf_spectacular.types import OpenApiTypes
12-
from drf_spectacular.utils import OpenApiParameter, extend_schema
12+
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
1313
from organizations.models import Organization, OrganizationMember
1414
from organizations.serializers import (
1515
OrganizationIdSerializer,
@@ -231,9 +231,10 @@ def get_queryset(self):
231231
),
232232
],
233233
responses={
234-
204: 'Member deleted successfully.',
235-
405: 'User cannot soft delete self.',
236-
404: 'Member not found',
234+
204: OpenApiResponse(description='Member deleted successfully.'),
235+
405: OpenApiResponse(description='User cannot soft delete self.'),
236+
404: OpenApiResponse(description='Member not found'),
237+
403: OpenApiResponse(description='You can delete members only for your current active organization'),
237238
},
238239
extensions={
239240
'x-fern-sdk-group-name': ['organizations', 'members'],

0 commit comments

Comments
 (0)