mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-17 18:32:35 +00:00
Remove accidentally included filters_disabled field from api endpoint and update api docs so they include field_options.
This commit is contained in:
parent
222021eafd
commit
781cde650d
12 changed files with 136 additions and 53 deletions
backend
src/baserow
api
contrib/database/api
tests/baserow
web-frontend/modules/database/services
|
@ -148,7 +148,7 @@ def allowed_includes(*allowed):
|
|||
"""
|
||||
A view method decorator that checks which allowed includes are in the GET
|
||||
parameters of the request. The allowed arguments are going to be added to the
|
||||
view method kwargs and if they are in the includes GET parameter the value will
|
||||
view method kwargs and if they are in the `include` GET parameter the value will
|
||||
be True.
|
||||
|
||||
Imagine this request:
|
||||
|
@ -174,7 +174,7 @@ def allowed_includes(*allowed):
|
|||
def validate_decorator(func):
|
||||
def func_wrapper(*args, **kwargs):
|
||||
request = get_request(args)
|
||||
raw_include = request.GET.get('includes', None)
|
||||
raw_include = request.GET.get('include', None)
|
||||
includes = raw_include.split(',') if raw_include else []
|
||||
|
||||
for include in allowed:
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from baserow.contrib.database.api.views.grid.serializers import \
|
||||
GridViewFieldOptionsField
|
||||
|
||||
def get_example_pagination_serializer_class(results_serializer_class):
|
||||
|
||||
def get_example_pagination_serializer_class(results_serializer_class,
|
||||
add_field_options=False):
|
||||
"""
|
||||
Generates a pagination like response serializer that has the provided serializer
|
||||
class as results. It is only used for example purposes in combination with the
|
||||
|
@ -9,26 +13,35 @@ def get_example_pagination_serializer_class(results_serializer_class):
|
|||
|
||||
:param results_serializer_class: The serializer class that needs to be added as
|
||||
results.
|
||||
:param add_field_options: When true will include the field_options field on the
|
||||
returned serializer.
|
||||
:type results_serializer_class: Serializer
|
||||
:return: The generated pagination serializer.
|
||||
:rtype: Serializer
|
||||
"""
|
||||
|
||||
fields = {
|
||||
'count': serializers.IntegerField(help_text='The total amount of results.'),
|
||||
'next': serializers.URLField(
|
||||
allow_blank=True,
|
||||
allow_null=True,
|
||||
help_text='URL to the next page.'
|
||||
),
|
||||
'previous': serializers.URLField(
|
||||
allow_blank=True,
|
||||
allow_null=True,
|
||||
help_text='URL to the previous page.'
|
||||
),
|
||||
'results': results_serializer_class(many=True)
|
||||
}
|
||||
|
||||
serializer_name = 'PaginationSerializer'
|
||||
if add_field_options:
|
||||
fields['field_options'] = GridViewFieldOptionsField(required=False)
|
||||
serializer_name = serializer_name + 'WithFieldOptions'
|
||||
|
||||
return type(
|
||||
'PaginationSerializer' + results_serializer_class.__name__,
|
||||
serializer_name + results_serializer_class.__name__,
|
||||
(serializers.Serializer,),
|
||||
{
|
||||
'count': serializers.IntegerField(help_text='The total amount of results.'),
|
||||
'next': serializers.URLField(
|
||||
allow_blank=True,
|
||||
allow_null=True,
|
||||
help_text='URL to the next page.'
|
||||
),
|
||||
'previous': serializers.URLField(
|
||||
allow_blank=True,
|
||||
allow_null=True,
|
||||
help_text='URL to the previous page.'
|
||||
),
|
||||
'results': results_serializer_class(many=True)
|
||||
}
|
||||
fields
|
||||
)
|
||||
|
|
|
@ -7,7 +7,6 @@ from baserow.api.serializers import get_example_pagination_serializer_class
|
|||
from baserow.core.utils import model_default_values, dict_to_object
|
||||
from baserow.contrib.database.fields.registries import field_type_registry
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -133,3 +132,6 @@ def get_example_row_serializer_class(add_id=False):
|
|||
example_pagination_row_serializer_class = get_example_pagination_serializer_class(
|
||||
get_example_row_serializer_class(True)
|
||||
)
|
||||
example_pagination_row_serializer_class_with_field_options = \
|
||||
get_example_pagination_serializer_class(
|
||||
get_example_row_serializer_class(True), add_field_options=True)
|
||||
|
|
|
@ -12,10 +12,11 @@ from baserow.api.pagination import PageNumberPagination
|
|||
from baserow.api.schemas import get_error_schema
|
||||
from baserow.core.exceptions import UserNotInGroupError
|
||||
from baserow.contrib.database.api.rows.serializers import (
|
||||
get_row_serializer_class, RowSerializer
|
||||
get_row_serializer_class, RowSerializer,
|
||||
example_pagination_row_serializer_class_with_field_options
|
||||
)
|
||||
from baserow.contrib.database.api.rows.serializers import (
|
||||
get_example_row_serializer_class, example_pagination_row_serializer_class
|
||||
get_example_row_serializer_class
|
||||
)
|
||||
from baserow.contrib.database.api.views.grid.serializers import GridViewSerializer
|
||||
from baserow.contrib.database.views.exceptions import (
|
||||
|
@ -92,7 +93,7 @@ class GridViewView(APIView):
|
|||
'`list_database_table_view_sortings` endpoints.'
|
||||
),
|
||||
responses={
|
||||
200: example_pagination_row_serializer_class,
|
||||
200: example_pagination_row_serializer_class_with_field_options,
|
||||
400: get_error_schema(['ERROR_USER_NOT_IN_GROUP']),
|
||||
404: get_error_schema(['ERROR_GRID_DOES_NOT_EXIST'])
|
||||
}
|
||||
|
@ -109,7 +110,7 @@ class GridViewView(APIView):
|
|||
else the page number pagination.
|
||||
|
||||
Optionally the field options can also be included in the response if the the
|
||||
`field_options` are provided in the includes GET parameter.
|
||||
`field_options` are provided in the include GET parameter.
|
||||
"""
|
||||
|
||||
view_handler = ViewHandler()
|
||||
|
@ -144,7 +145,8 @@ class GridViewView(APIView):
|
|||
# but when added to the context the fields don't have to be fetched from
|
||||
# the database again when checking if they exist.
|
||||
context = {'fields': [o['field'] for o in model._field_objects.values()]}
|
||||
response.data.update(**GridViewSerializer(view, context=context).data)
|
||||
serialized_view = GridViewSerializer(view, context=context).data
|
||||
response.data['field_options'] = serialized_view['field_options']
|
||||
|
||||
return response
|
||||
|
||||
|
|
|
@ -82,8 +82,8 @@ class UpdateViewSortSerializer(serializers.ModelSerializer):
|
|||
class ViewSerializer(serializers.ModelSerializer):
|
||||
type = serializers.SerializerMethodField()
|
||||
table = TableSerializer()
|
||||
filters = ViewFilterSerializer(many=True, source='viewfilter_set')
|
||||
sortings = ViewSortSerializer(many=True, source='viewsort_set')
|
||||
filters = ViewFilterSerializer(many=True, source='viewfilter_set', required=False)
|
||||
sortings = ViewSortSerializer(many=True, source='viewsort_set', required=False)
|
||||
|
||||
class Meta:
|
||||
model = View
|
||||
|
@ -95,15 +95,23 @@ class ViewSerializer(serializers.ModelSerializer):
|
|||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
include_filters = kwargs.pop('filters') if 'filters' in kwargs else False
|
||||
include_sortings = kwargs.pop('sortings') if 'sortings' in kwargs else False
|
||||
context = kwargs.setdefault("context", {})
|
||||
context['include_filters'] = kwargs.pop('filters', False)
|
||||
context['include_sortings'] = kwargs.pop('sortings', False)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if not include_filters:
|
||||
self.fields.pop('filters')
|
||||
def to_representation(self, instance):
|
||||
# We remove the fields in to_representation rather than __init__ as otherwise
|
||||
# drf-spectacular will not know that filters and sortings exist as optional
|
||||
# return fields. This way the fields are still dynamic and also show up in the
|
||||
# OpenAPI specification.
|
||||
if not self.context['include_filters']:
|
||||
self.fields.pop('filters', None)
|
||||
|
||||
if not include_sortings:
|
||||
self.fields.pop('sortings')
|
||||
if not self.context['include_sortings']:
|
||||
self.fields.pop('sortings', None)
|
||||
|
||||
return super().to_representation(instance)
|
||||
|
||||
@extend_schema_field(OpenApiTypes.STR)
|
||||
def get_type(self, instance):
|
||||
|
|
|
@ -54,7 +54,20 @@ class ViewsView(APIView):
|
|||
type=OpenApiTypes.INT,
|
||||
description='Returns only views of the table related to the provided '
|
||||
'value.'
|
||||
)
|
||||
),
|
||||
OpenApiParameter(
|
||||
name='include',
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.STR,
|
||||
description=(
|
||||
'A comma separated list of extra attributes to include on each '
|
||||
'view in the response. The supported attributes are `filters` and '
|
||||
'`sortings`. '
|
||||
'For example `include=filters,sortings` will add the attributes '
|
||||
'`filters` and `sortings` to every returned view, containing '
|
||||
'a list of the views filters and sortings respectively.'
|
||||
)
|
||||
),
|
||||
],
|
||||
tags=['Database table views'],
|
||||
operation_id='list_database_table_views',
|
||||
|
@ -117,7 +130,20 @@ class ViewsView(APIView):
|
|||
type=OpenApiTypes.INT,
|
||||
description='Creates a view for the table related to the provided '
|
||||
'value.'
|
||||
)
|
||||
),
|
||||
OpenApiParameter(
|
||||
name='include',
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.STR,
|
||||
description=(
|
||||
'A comma separated list of extra attributes to include on each '
|
||||
'view in the response. The supported attributes are `filters` and '
|
||||
'`sortings`. '
|
||||
'For example `include=filters,sortings` will add the attributes '
|
||||
'`filters` and `sortings` to every returned view, containing '
|
||||
'a list of the views filters and sortings respectively.'
|
||||
)
|
||||
),
|
||||
],
|
||||
tags=['Database table views'],
|
||||
operation_id='create_database_table_view',
|
||||
|
@ -176,7 +202,20 @@ class ViewView(APIView):
|
|||
location=OpenApiParameter.PATH,
|
||||
type=OpenApiTypes.INT,
|
||||
description='Returns the view related to the provided value.'
|
||||
)
|
||||
),
|
||||
OpenApiParameter(
|
||||
name='include',
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.STR,
|
||||
description=(
|
||||
'A comma separated list of extra attributes to include on the '
|
||||
'returned view. The supported attributes are are `filters` and '
|
||||
'`sortings`. '
|
||||
'For example `include=filters,sortings` will add the attributes '
|
||||
'`filters` and `sortings` to every returned view, containing '
|
||||
'a list of the views filters and sortings respectively.'
|
||||
)
|
||||
),
|
||||
],
|
||||
tags=['Database table views'],
|
||||
operation_id='get_database_table_view',
|
||||
|
@ -219,7 +258,20 @@ class ViewView(APIView):
|
|||
location=OpenApiParameter.PATH,
|
||||
type=OpenApiTypes.INT,
|
||||
description='Updates the view related to the provided value.'
|
||||
)
|
||||
),
|
||||
OpenApiParameter(
|
||||
name='include',
|
||||
location=OpenApiParameter.QUERY,
|
||||
type=OpenApiTypes.STR,
|
||||
description=(
|
||||
'A comma separated list of extra attributes to include on the '
|
||||
'returned view. The supported attributes are are `filters` and '
|
||||
'`sortings`. '
|
||||
'For example `include=filters,sortings` will add the attributes '
|
||||
'`filters` and `sortings` to every returned view, containing '
|
||||
'a list of the views filters and sortings respectively.'
|
||||
)
|
||||
),
|
||||
],
|
||||
tags=['Database table views'],
|
||||
operation_id='update_database_table_view',
|
||||
|
|
|
@ -250,7 +250,7 @@ def test_allowed_includes():
|
|||
|
||||
request = Request(factory.get(
|
||||
'/some-page/',
|
||||
data={'includes': 'test_1,test_2'},
|
||||
data={'include': 'test_1,test_2'},
|
||||
))
|
||||
|
||||
@allowed_includes('test_1', 'test_3')
|
||||
|
@ -262,7 +262,7 @@ def test_allowed_includes():
|
|||
|
||||
request = Request(factory.get(
|
||||
'/some-page/',
|
||||
data={'includes': 'test_3'},
|
||||
data={'include': 'test_3'},
|
||||
))
|
||||
|
||||
@allowed_includes('test_1', 'test_3')
|
||||
|
|
|
@ -218,7 +218,7 @@ def test_list_rows_include_field_options(api_client, data_fixture):
|
|||
url = reverse('api:database:views:grid:list', kwargs={'view_id': grid.id})
|
||||
response = api_client.get(
|
||||
url,
|
||||
{'includes': 'field_options'},
|
||||
{'include': 'field_options'},
|
||||
**{'HTTP_AUTHORIZATION': f'JWT {token}'}
|
||||
)
|
||||
response_json = response.json()
|
||||
|
@ -230,6 +230,7 @@ def test_list_rows_include_field_options(api_client, data_fixture):
|
|||
assert response_json['field_options'][str(number_field.id)]['width'] == 200
|
||||
assert response_json['field_options'][str(number_field.id)]['hidden'] is False
|
||||
assert response_json['field_options'][str(number_field.id)]['order'] == 32767
|
||||
assert 'filters_disabled' not in response_json
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
|
|
@ -98,7 +98,7 @@ def test_list_views_including_filters(api_client, data_fixture):
|
|||
assert 'filters' not in response_json[1]
|
||||
|
||||
response = api_client.get(
|
||||
'{}?includes=filters'.format(reverse(
|
||||
'{}?include=filters'.format(reverse(
|
||||
'api:database:views:list',
|
||||
kwargs={'table_id': table_1.id}
|
||||
)),
|
||||
|
@ -148,7 +148,7 @@ def test_list_views_including_sortings(api_client, data_fixture):
|
|||
assert 'sortings' not in response_json[1]
|
||||
|
||||
response = api_client.get(
|
||||
'{}?includes=sortings'.format(reverse(
|
||||
'{}?include=sortings'.format(reverse(
|
||||
'api:database:views:list',
|
||||
kwargs={'table_id': table_1.id}
|
||||
)),
|
||||
|
@ -232,7 +232,7 @@ def test_create_view(api_client, data_fixture):
|
|||
assert 'sortings' not in response_json
|
||||
|
||||
response = api_client.post(
|
||||
'{}?includes=filters,sortings'.format(
|
||||
'{}?include=filters,sortings'.format(
|
||||
reverse('api:database:views:list', kwargs={'table_id': table.id})
|
||||
),
|
||||
{
|
||||
|
@ -318,7 +318,7 @@ def test_get_view(api_client, data_fixture):
|
|||
|
||||
url = reverse('api:database:views:item', kwargs={'view_id': view.id})
|
||||
response = api_client.get(
|
||||
'{}?includes=filters,sortings'.format(url),
|
||||
'{}?include=filters,sortings'.format(url),
|
||||
format='json',
|
||||
HTTP_AUTHORIZATION=f'JWT {token}'
|
||||
)
|
||||
|
@ -417,7 +417,7 @@ def test_update_view(api_client, data_fixture):
|
|||
filter_1 = data_fixture.create_view_filter(view=view)
|
||||
url = reverse('api:database:views:item', kwargs={'view_id': view.id})
|
||||
response = api_client.patch(
|
||||
'{}?includes=filters,sortings'.format(url),
|
||||
'{}?include=filters,sortings'.format(url),
|
||||
{'filter_type': 'AND'},
|
||||
format='json',
|
||||
HTTP_AUTHORIZATION=f'JWT {token}'
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
* Made it possible to re-order fields in a grid view.
|
||||
* Show the number of filters and sorts active in the header of a grid view.
|
||||
* The first user to sign-up after installation now gets given staff status.
|
||||
* Rename the "includes" get parameter across all API endpoints to "include" to be
|
||||
consistent.
|
||||
* Add missing include query parameter and corresponding response attributes to API docs.
|
||||
* Remove incorrectly included "filters_disabled" field from
|
||||
list_database_table_grid_view_rows api endpoint.
|
||||
* Show an error to the user when the web socket connection could not be made and the
|
||||
reconnect loop stops.
|
||||
* Fixed 100X backend web socket errors when refreshing the page.
|
||||
|
|
|
@ -4,18 +4,18 @@ export default (client) => {
|
|||
const config = {
|
||||
params: {},
|
||||
}
|
||||
const includes = []
|
||||
const include = []
|
||||
|
||||
if (includeFilters) {
|
||||
includes.push('filters')
|
||||
include.push('filters')
|
||||
}
|
||||
|
||||
if (includeSortings) {
|
||||
includes.push('sortings')
|
||||
include.push('sortings')
|
||||
}
|
||||
|
||||
if (includes.length > 0) {
|
||||
config.params.includes = includes.join(',')
|
||||
if (include.length > 0) {
|
||||
config.params.include = include.join(',')
|
||||
}
|
||||
|
||||
return client.get(`/database/views/table/${tableId}/`, config)
|
||||
|
|
|
@ -12,7 +12,7 @@ export default (client) => {
|
|||
limit,
|
||||
},
|
||||
}
|
||||
const includes = []
|
||||
const include = []
|
||||
|
||||
if (offset !== null) {
|
||||
config.params.offset = offset
|
||||
|
@ -23,11 +23,11 @@ export default (client) => {
|
|||
}
|
||||
|
||||
if (includeFieldOptions) {
|
||||
includes.push('field_options')
|
||||
include.push('field_options')
|
||||
}
|
||||
|
||||
if (includes.length > 0) {
|
||||
config.params.includes = includes.join(',')
|
||||
if (include.length > 0) {
|
||||
config.params.include = include.join(',')
|
||||
}
|
||||
|
||||
return client.get(`/database/views/grid/${gridId}/`, config)
|
||||
|
|
Loading…
Add table
Reference in a new issue