Beispiel #1
0
    def retrieve(self, request, pk=None, **kwargs):
        """
        Download the JSON release file using the ReleaseInfo object_id
        Example: http://127.0.0.1:8000/api/release-download/18bc23da-cdbf-420e-a6aa-3d9ecdb10c20/
        """
        release_info = get_object_or_404(ReleaseInfo, object_id=pk)

        if not release_info.dp_release_json_file:
            user_msg = 'The Release does not include a JSON file.'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        # get an open file handle
        try:
            file_handle = release_info.dp_release_json_file.open()
        except ValueError as err_obj:
            user_msg = f'Not able to read the JSON Release file. (1) ({err_obj})'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)
        except Exception as err_obj:
            user_msg = f'Not able to read the JSON Release file. (2) ({err_obj})'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        # send file
        response = FileResponse(file_handle, content_type='application/json')
        response['Content-Length'] = release_info.dp_release_json_file.size
        download_fname = f'release_{release_info.object_id}.json'
        response[
            'Content-Disposition'] = f'attachment; filename="{download_fname}"'

        return response
Beispiel #2
0
    def pdf(self, request, pk=None):
        """
        Download the PDF release file using the ReleaseInfo object_id
        Note: URL linked to code in opendp_apps/analysis/models.py ->  download_pdf_url()
        Example: http://127.0.0.1:8000/api/release-download/18bc23da-cdbf-420e-a6aa-3d9ecdb10c20/pdf/
        """
        release_info = get_object_or_404(ReleaseInfo, object_id=pk)

        if not release_info.dp_release_pdf_file:
            user_msg = 'The Release does not include a PDF file.'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        # get an open file handle
        try:
            file_handle = release_info.dp_release_pdf_file.open()
        except ValueError as err_obj:
            user_msg = f'Not able to read the PDF Release file. (1) ({err_obj})'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)
        except Exception as err_obj:
            user_msg = f'Not able to read the PDF Release file. (2) ({err_obj})'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        # send file
        response = FileResponse(file_handle, content_type='application/pdf')
        response['Content-Length'] = release_info.dp_release_pdf_file.size
        download_fname = f'release_{release_info.object_id}.pdf'
        response[
            'Content-Disposition'] = f'attachment; filename="{download_fname}"'

        return response
Beispiel #3
0
    def list(self, request):
        """Only used so that these endpoints show up in the docs"""
        user_msg = ('ProfilingViewSet: custom actions only.'
                    ' In API docs, see "Extra Actions"')
        return Response(get_json_error(user_msg),
                        status=status.HTTP_501_NOT_IMPLEMENTED)

        return Response(get_json_success())
Beispiel #4
0
    def retrieve_profile(self, request, *args, **kwargs):
        """Retrieve the DataSetInfo.profile_variables in JSON format.
        - Input: DataSetInfo.object_id (UUID in string format)
        - Output: DataSetInfo.profile_variables in JSON format
        NOTES:
        - The logged in user must match the DataSetInfo.creator
        """
        print('\n>>request', request)
        print('\n>>request.data', request.data, type(request.data))

        # Is this a object_id a valid UUID?
        #
        ois = DatasetObjectIdSerializer(data=request.data)
        if not ois.is_valid():
            print(ois.errors)
            if 'object_id' in ois.errors:
                user_msg = '"object_id" error: %s' % (
                    ois.errors['object_id'][0])
            else:
                user_msg = 'Not a valid "object_id"'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        # Is there a related DataSetInfo where the logged in user is the
        #   DataSetInfo creator?
        #
        dsi_info = ois.get_dataset_info_with_user_check(request.user)
        if not dsi_info.success:
            return Response(get_json_error(dsi_info.message),
                            status=status.HTTP_404_NOT_FOUND)

        # Does the profile exist?
        #
        dsi_object = dsi_info.data
        if not dsi_object.profile_variables:
            user_msg = 'Dataset not profiled'
            # status for profile?
            return Response(get_json_error(user_msg))

        # Profile found!
        #
        return Response(
            get_json_success('Profile found',
                             data=dsi_object.get_profile_variables()))
Beispiel #5
0
    def run_direct_profile(self, request, *args, **kwargs):
        """TEST ONLY - Profile a DataSetInfo object, returning the DataSetInfo.profile_variables in JSON format.
        - Input: DataSetInfo.object_id (UUID in string format)
        - Output: DataSetInfo.profile_variables in JSON format
        NOTES:
        - TEST ONLY: Uses the main web server thread
        - The logged in user must match the DataSetInfo.creator
        - The response is returned asynchronously, via a websocket
        - If the profile already exists, it will be returned asynchronously.
        - If the DataSetInfo object is a DataverseFileInfo object, if necessary, this endpoint will both download the dataset in order to profile it.
        """
        # Is this a object_id a valid UUID?
        #
        ois = DatasetObjectIdSerializer(data=request.data)
        if not ois.is_valid():
            #print(ois.errors)
            if 'object_id' in ois.errors:
                user_msg = '"object_id" error: %s' % (
                    ois.errors['object_id'][0])
            else:
                user_msg = 'Not a valid "object_id"'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        # Is there a related DataSetInfo where the logged in user is the
        #   DataSetInfo creator?
        #
        dsi_info = ois.get_dataset_info_with_user_check(request.user)
        if not dsi_info.success:
            return Response(get_json_error(dsi_info.message),
                            status=status.HTTP_404_NOT_FOUND)

        websocket_id = get_websocket_id(request)

        ddi_info = profile_dataset_info(ois.get_object_id(),
                                        websocket_id=websocket_id)
        if not ddi_info.success:
            return Response(get_json_error(ddi_info.message))

        dp_util = ddi_info.data

        user_msg = ('Profiling complete.')
        return Response(
            get_json_success(user_msg, data=dp_util.get_profile_variables()))
Beispiel #6
0
    def create(self, request, *args, **kwargs):
        """
        Create an AnalysisPlan object with default values
        """
        # Is this a object_id a valid UUID?
        #
        ois = DatasetObjectIdSerializer(data=request.data)
        if not ois.is_valid():
            #print(ois.errors)
            if 'object_id' in ois.errors:
                user_msg = '"object_id" error: %s' % (
                    ois.errors['object_id'][0])
            else:
                user_msg = 'Not a valid "object_id"'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        # Is there a related DataSetInfo where the logged in user is the
        #   DataSetInfo creator?
        #
        dsi_info = ois.get_dataset_info_with_user_check(request.user)
        if not dsi_info.success:
            return Response(get_json_error(dsi_info.message),
                            status=status.HTTP_404_NOT_FOUND)

        # Use the AnalysisPlanUtil to create an AnalysisPlan
        #   with default values
        #
        plan_util = AnalysisPlanUtil.create_plan(ois.get_object_id(),
                                                 request.user)

        # Did AnalysisPlan creation work?
        if plan_util.success:
            # Yes, it worked!
            new_plan = plan_util.data  # "data" holds the AnalysisPlan object
            serializer = AnalysisPlanSerializer(new_plan)  # serialize the data

            # Return it
            return Response(serializer.data, status=status.HTTP_201_CREATED)

        # Nope! Error encountered!
        return Response(get_json_error(plan_util.message),
                        status=plan_util.data)
def manifest_test_params_view(request, object_id):
    """
    Return the ManifestTestParams in JSON format.
    (Limit this to superusers)
    """
    mparams = ManifestTestParams.objects.filter(object_id=object_id).first()
    if not mparams:
        return JsonResponse(get_json_error('Object not found'),
                            status=HTTPStatus.NOT_FOUND)

    return JsonResponse(get_json_success('Success', data=mparams.as_dict()))
Beispiel #8
0
    def partial_update(self, request, *args, **kwargs):
        """Make updates to the AnalysisPlan object"""
        # print('>>> partial_update: ', request.data)
        acceptable_fields = ['variable_info', 'dp_statistics', 'user_step']
        problem_fields = []
        fields_to_update = []
        for field in request.data.keys():
            if field not in acceptable_fields:
                problem_fields.append(field)
            else:
                fields_to_update.append(field)
        if problem_fields:
            problem_field_list = ', '.join([str(f) for f in problem_fields])
            user_msg = f'{astatic.ERR_MSG_FIELDS_NOT_UPDATEABLE}: {problem_field_list}'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        if not fields_to_update:
            return Response(get_json_error(f'There are no fields to update'),
                            status=status.HTTP_400_BAD_REQUEST)

        return super(AnalysisPlanViewSet,
                     self).partial_update(request, *args, **kwargs)
    def list(self, request, *args, **kwargs):
        """Retrieve all active RegisteredDataverse objects"""
        serializer = RegisteredDataverseSerializer(self.queryset, many=True)

        num_dvs = len(serializer.data)
        success = False
        message = "No registered Dataverses found."
        if num_dvs > 0:
            success = True
            message = f"{num_dvs} registered Dataverse(s) found."

        if success:
            return Response(get_json_success(message,
                                             data=dict(
                                                 count=num_dvs,
                                                 dataverses=serializer.data)),
                            status=status.HTTP_200_OK)

        return Response(get_json_error(message),
                        status=status.HTTP_404_NOT_FOUND)
Beispiel #10
0
    def create(self, request, *args, **kwargs):
        """Expects JSON. Given object_ids for OpenDPUser and DataverseHandoff objects,
        retrieve the user's information from Dataverse and create a DataverseUser"""

        # ----------------------------------
        # Validate the input
        # ----------------------------------
        # print(f"data: {request.data}")
        request_data = request.data.copy()

        user_id = request.data.get('user')
        handoff_id = request.data.get('dv_handoff')

        request_data['handoff'] = handoff_id
        request_data['user'] = user_id

        handoff_obj = get_object_or_error_response(DataverseHandoff,
                                                   object_id=handoff_id)

        try:
            dataverse_user = DataverseUser.objects.get(
                user__object_id=user_id,
                dv_installation=handoff_obj.dv_installation)
            opendp_user = dataverse_user.user

        except DataverseUser.DoesNotExist:
            # ----------------------------------
            # Create the DataverseUser object
            # ----------------------------------
            dataverse_user_serializer = DataverseUserSerializer(
                data=request_data, context={'request': request})
            if not dataverse_user_serializer.is_valid():
                # print("INVALID SERIALIZER")
                return Response(dataverse_user_serializer.errors,
                                status=status.HTTP_400_BAD_REQUEST)

            try:
                dataverse_user = dataverse_user_serializer.save()
            except DataverseHandoff.DoesNotExist:
                return Response(dataverse_user_serializer.errors,
                                status=status.HTTP_400_BAD_REQUEST)
            except DataverseUser.DoesNotExist:
                return Response(dataverse_user_serializer.errors,
                                status=status.HTTP_400_BAD_REQUEST)

            opendp_user = dataverse_user_serializer.validated_data.get('user')

        # ----------------------------------
        # Call the Dataverse API
        # ----------------------------------
        site_url = handoff_obj.dv_installation.dataverse_url
        # print('-- site_url', site_url)
        api_general_token = dataverse_user.dv_general_token

        dataverse_client = DataverseClient(site_url, api_general_token)
        try:
            dataverse_response = dataverse_client.get_user_info(
                user_api_token=api_general_token)
        except InvalidSchema:
            return Response(
                get_json_error(f'The Site {site_url} is not valid'),
                status=status.HTTP_400_BAD_REQUEST)
        except JSONDecodeError:
            return Response(
                get_json_error(f'Error reading data from {site_url}'),
                status=status.HTTP_400_BAD_REQUEST)

        if dataverse_response.success is not True:
            return Response(get_json_error(dataverse_response.message),
                            status=status.HTTP_400_BAD_REQUEST)

        try:
            handler = DataverseUserHandler(opendp_user.id, site_url,
                                           api_general_token,
                                           dataverse_response.__dict__)
            update_response = handler.update_dataverse_user()
        except DataverseResponseError as ex:
            return Response(get_json_error(f'Error {ex}'),
                            status=status.HTTP_400_BAD_REQUEST)

        return Response(get_json_success(
            'success', data={'dv_user': dataverse_user.object_id}),
                        status=status.HTTP_201_CREATED)
Beispiel #11
0
    def update(self, request, object_id=None, *args, **kwargs):
        """NOT REALLY USED!!! e.g. create is really create_or_update"""
        """Update the Dataverse User. Expects JSON"""
        # ----------------------------------
        # Validate the input
        # ----------------------------------
        print(f"data: {request.data}\tpk: {object_id}")
        dataverse_user = get_object_or_error_response(DataverseUser,
                                                      object_id=object_id)
        opendp_user = dataverse_user.user
        request.data['user'] = opendp_user.object_id

        dataverse_user_serializer = DataverseUserSerializer(
            data=request.data, context={'request': request})
        if dataverse_user_serializer.is_valid():
            try:
                dataverse_user = dataverse_user_serializer.update(
                    dataverse_user, request.data)
            except DataverseHandoff.DoesNotExist:
                return JsonResponse(
                    {
                        'success': False,
                        'message': 'No such DataVerse exists'
                    },
                    status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response(dataverse_user_serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

        opendp_user = dataverse_user_serializer.validated_data.get('user')
        if not opendp_user:
            return Response({
                'success': False,
                'message': 'No OpenDP user found'
            })

        # ----------------------------------
        # Call the Dataverse API
        # ----------------------------------
        dv_handoff = get_object_or_error_response(
            DataverseHandoff, object_id=request.data['dv_handoff'])
        site_url = dv_handoff.dv_installation.dataverse_url
        api_general_token = dataverse_user.dv_general_token
        dataverse_client = DataverseClient(site_url, api_general_token)
        try:
            dataverse_response = dataverse_client.get_user_info(
                user_api_token=api_general_token)
        except InvalidSchema:
            return JsonResponse(
                get_json_error(f'The Site {site_url} is not valid'),
                status=400)
        except JSONDecodeError:
            return JsonResponse(
                get_json_error(f'Error reading data from {site_url}'),
                status=status.HTTP_400_BAD_REQUEST)

        if dataverse_response.success is not True:
            return JsonResponse(get_json_error(dataverse_response.message),
                                status=400)

        # ----------------------------------
        # Update the DataverseUser object
        # ----------------------------------
        try:
            handler = DataverseUserHandler(opendp_user.id, site_url,
                                           api_general_token,
                                           dataverse_response.__dict__)
            update_resp = handler.update_dataverse_user()
            if update_resp.success:
                updated_dv_user = update_resp.data
                updated_dv_user.save()
            else:
                return JsonResponse(get_json_error(update_resp.message),
                                    status=status.HTTP_400_BAD_REQUEST)
        except DataverseResponseError as ex:
            return JsonResponse(get_json_error(f'Error {ex}'),
                                status=status.HTTP_400_BAD_REQUEST)

        return JsonResponse(get_json_success(
            'updated', data=dict(dv_user=updated_dv_user.object_id)),
                            status=201)
Beispiel #12
0
    def create(self, request, *args, **kwargs):
        """
        Note: No data is saved. This endpoint is used for validation.

        endpoint: /api/validation/

        Example POST input:
            {
                "analysis_plan_id": "616b5167-4ce8-4def-85dc-6f0d8de2316c",
                "dp_statistics": [
                    {
                        "statistic": "mean",
                        "variable": "EyeHeight",
                        "epsilon": 0.6,
                        "delta": 0,
                        "error": "",
                        "missing_values_handling": "insert_fixed",
                        "handle_as_fixed": false,
                        "fixed_value": "5.0",
                        "locked": false,
                        "label": "EyeHeight"
                    }
                ]
            }

        -- Example outputs --

        (1) Overall error
            Status code: 400
                {
                    "success": false,
                    "message": "The depositor setup info has an invalid epsilon value: 4.0"
                }

        (2) Single statistic error -- even if only 1 statistic submitted
            Status code: 200  - NOTE status code is 200!
            {
                "success": true,
                "message": "validation results returned",
                "data": [
                    {
                        "var_name": "BlinkDuration",
                        "statistic": "mean",
                        "valid": false,
                        "message": "As a rule of thumb, epsilon should not be less than 0.001 nor greater than 1."
                    }
                ]
            }

        (2) Single statistic success -- even if only 1 statistic submitted
            Status code: 200  - NOTE status code is 200!

            {
                "success": true,
                "message": "validation results returned",
                "data": [
                    {
                        "var_name": "EyeHeight",
                        "statistic": "mean",
                        "valid": true,
                        "message": null
                    }
                ]
            }

        (3) Mixed success and error -- even if only 1 statistic submitted
            Status code: 200  - NOTE status code is 200!
            {
                "success": true,
                "message": "validation results returned",
                "data": [
                    {
                        "var_name": "EyeHeight",
                        "statistic": "mean",
                        "valid": true,
                        "message": null
                    },
                    {
                        "var_name": "BlinkDuration",
                        "statistic": "mean",
                        "valid": false,
                        "message": "The running epsilon (1.45) exceeds the max epsilon (1.0)"
                    }
                ]
            }

        """
        #print('>> ReleaseView.create >>>', request.data)
        release_info_serializer = ReleaseValidationSerializer(
            data=request.data)
        if not release_info_serializer.is_valid():
            print('release_info_serializer.errors',
                  release_info_serializer.errors)
            return Response(get_json_error(
                'Field validation failed',
                errors=release_info_serializer.errors),
                            status=status.HTTP_200_OK)
            #status=status.HTTP_400_BAD_REQUEST)

        save_result = release_info_serializer.save(**dict(
            opendp_user=request.user))
        #print(save_result.success)
        if not save_result.success:
            #print(save_result.message)

            return Response(get_json_error(save_result.message),
                            status=status.HTTP_400_BAD_REQUEST)

        #print(save_result.data)
        return Response(get_json_success('validation results returned',
                                         data=save_result.data),
                        status=status.HTTP_200_OK)
Beispiel #13
0
    def create(self, request, *args, **kwargs):
        """
        Override create to create a release based on a saved/pre-validated AnalysisPlan.dp_statistics

        endpoint: /api/release/

        Example POST input: `{"analysis_plan_id": "616b5167-4ce8-4def-85dc-6f0d8de2316c"}`

       -- Example outputs --

        (1) Overall error
            Status code: 400
                {
                    "success": false,
                    "message": "The statistic 'EyeHeight' had error xyz!"
                }

        (2) Release success
            Status code: 201
            {
                    "success": true,
                    "message": "release worked!",
                    "data":
                       (see: opendp_apps.release_info_formatter.get_release_data())

        """
        # Get the AnalysisPlan object_id
        #   - Bit redundant in the serializer re: retrieving plan but only using object_id--but okay!
        #     - e.g. Passing along the object_id only will lead to later running chain
        #       in a separate process and responding by websocket/lambda, etc.
        #
        serializer = AnalysisPlanObjectIdSerializer(data=request.data)
        if not serializer.is_valid():
            print(serializer.errors)
            if 'object_id' in serializer.errors:
                user_msg = '"object_id" error: %s' % (
                    serializer.errors['object_id'][0])
            else:
                user_msg = 'Not a valid AnalysisPlan "object_id"'
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        # We have a good object_id!
        #
        analysis_plan_id = serializer.get_object_id()

        # For longer releases, Async this!!
        # Async: the validate_util process!
        validate_util = ValidateReleaseUtil.compute_mode(
            request.user, analysis_plan_id, run_dataverse_deposit=True)
        if validate_util.has_error():
            # This is a big error, check for it before evaluating individual statistics
            #
            user_msg = validate_util.get_err_msg()
            print('release_view.create(...) user_msg', user_msg)

            # Can you return a 400 / raise an Exception here with the error message?
            # How should this be used?
            return Response(get_json_error(user_msg),
                            status=status.HTTP_400_BAD_REQUEST)

        # It worked! Return the release!
        release_info_obj = validate_util.get_new_release_info_object()
        serializer = ReleaseInfoSerializer(release_info_obj,
                                           context={'request': request})
        return Response(data=serializer.data, status=status.HTTP_201_CREATED)