Source code for beat.web.dataformats.api
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
###############################################################################
# #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.web module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform is distributed in the hope that it will be useful, but #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
from django.shortcuts import get_object_or_404
from django.utils import six
from django.core.exceptions import ValidationError
from rest_framework.response import Response
from rest_framework.exceptions import ParseError
from rest_framework import serializers
from .models import DataFormat
from .serializers import DataFormatSerializer
from .serializers import FullDataFormatSerializer
from .serializers import DataFormatCreationSerializer
from ..common.responses import BadRequestResponse, ForbiddenResponse
from ..common.api import (CheckContributionNameView, ShareView, ListContributionView,
ListCreateContributionView, DiffView, RetrieveUpdateDestroyContributionView)
from ..common.utils import validate_restructuredtext, ensure_html
import simplejson as json
#----------------------------------------------------------
[docs]class CheckDataFormatNameView(CheckContributionNameView):
"""
This view sanitizes a data format name and
checks whether it is already used.
"""
model = DataFormat
#----------------------------------------------------------
#----------------------------------------------------------
[docs]class ListDataFormatView(ListContributionView):
"""
List all available data formats
"""
model = DataFormat
serializer_class = DataFormatSerializer
#----------------------------------------------------------
[docs]class ListCreateDataFormatsView(ListCreateContributionView):
"""
Read/Write end point that list the data formats available
from a given author and allows the creation of new data formats
"""
model = DataFormat
serializer_class = DataFormatSerializer
writing_serializer_class = DataFormatCreationSerializer
namespace = 'api_dataformats'
#----------------------------------------------------------
[docs]class RetrieveUpdateDestroyDataFormatsView(RetrieveUpdateDestroyContributionView):
"""
Read/Write/Delete endpoint for a given data format
"""
model = DataFormat
serializer_class = FullDataFormatSerializer
[docs] def put(self, request, author_name, object_name, version=None):
if version is None:
raise serializers.ValidationError({'version': 'A version number must be provided'})
try:
data = request.data
except ParseError as e:
raise serializers.ValidationError({'data': str(e)})
else:
if not data:
raise serializers.ValidationError({'data': 'Empty'})
if 'short_description' in data:
if not(isinstance(data['short_description'], six.string_types)):
raise serializers.ValidationError({'short_description': 'Invalid short_description data'})
short_description = data['short_description']
else:
short_description = None
if 'description' in data:
if not(isinstance(data['description'], six.string_types)):
raise serializers.ValidationError({'description': 'Invalid description data'})
description = data['description']
try:
validate_restructuredtext(description)
except ValidationError as errors:
raise serializers.ValidationError({'description': [error for error in errors]})
else:
description = None
if 'declaration' in data:
if isinstance(data['declaration'], dict):
json_declaration = data['declaration']
declaration = json.dumps(json_declaration, indent=4)
elif isinstance(data['declaration'], six.string_types):
declaration = data['declaration']
try:
json_declaration = json.loads(declaration)
except:
raise serializers.ValidationError({'declaration': 'Invalid declaration data'})
else:
raise serializers.ValidationError({'declaration': 'Invalid declaration data'})
if '#description' in json_declaration:
if short_description is not None:
raise serializers.ValidationError({'short_description': 'A short description is already provided in the data format declaration'})
short_description = json_declaration['#description']
elif short_description is not None:
json_declaration['#description'] = short_description
declaration = json.dumps(json_declaration, indent=4)
else:
declaration = None
json_declaration = None
if (short_description is not None) and (len(short_description) > DataFormat._meta.get_field('short_description').max_length):
raise serializers.ValidationError({'short_description': 'Short description too long'})
# Process the query string
if 'fields' in request.GET:
fields_to_return = request.GET['fields'].split(',')
else:
# Available fields (not returned by default):
# - html_description
fields_to_return = []
# Retrieve the data format
dataformat = get_object_or_404(DataFormat,
author__username__iexact=author_name,
name__iexact=object_name,
version=version)
# Check that the data format can still be modified (if applicable, the documentation
# can always be modified)
if (declaration is not None) and not(dataformat.modifiable()):
return ForbiddenResponse("The data format isn't modifiable anymore (either shared with someone else, or needed by an attestation)")
# Modification of the documentation
if (short_description is not None) and (declaration is None):
tmp_declaration = dataformat.declaration
tmp_declaration['#description'] = short_description
dataformat.declaration = tmp_declaration
if description is not None:
dataformat.description = description
# Modification of the declaration
if declaration is not None:
dataformat.declaration = declaration
# Save the data format model
try:
dataformat.save()
except Exception as e:
return BadRequestResponse(str(e))
# Nothing to return?
if len(fields_to_return) == 0:
return Response(status=204)
result = {}
# Retrieve the description in HTML format
if 'html_description' in fields_to_return:
description = dataformat.description
if len(description) > 0:
result['html_description'] = ensure_html(description)
else:
result['html_description'] = ''
return Response(result)
#----------------------------------------------------------
[docs]class DiffDataFormatView(DiffView):
"""
This view shows the differences between two data formats
"""
model = DataFormat