Exemplo n.º 1
0
    def get_json_format(self):
        """
        Retrieve details about a specific Resource.

        Returns
        -------
        Response object in JSON format
        """
        # Perform token, target, and action validation
        try:
            token = get_source_token(self.request)
            target_validation(self.source_target_name, self.action)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Fetch the proper function to call
        func = FunctionRouter.get_function(self.source_target_name,
                                           self.action)

        # Fetch the resource
        try:
            resource = func(token, self.source_resource_id)
        except PresQTResponseException as e:
            # Catch any errors that happen within the target fetch
            return Response(data={'error': e.data}, status=e.status_code)

        serializer = ResourceSerializer(instance=resource,
                                        context={
                                            'target_name':
                                            self.source_target_name,
                                            'request': self.request
                                        })

        return Response(serializer.data)
Exemplo n.º 2
0
    def transfer_patch(self):
        """
        Attempt to cancel a transfer job.
        """
        # Perform token validation. Read data from the process_info file.
        try:
            destination_token = get_destination_token(self.request)
            source_token = get_source_token(self.request)
            self.ticket_number = '{}_{}'.format(hash_tokens(source_token),
                                                hash_tokens(destination_token))
            process_data = get_process_info_data(self.ticket_number)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Wait until the spawned off process has started to cancel the transfer
        while process_data['resource_transfer_in'][
                'function_process_id'] is None:
            try:
                process_data = get_process_info_data(self.ticket_number)
            except json.decoder.JSONDecodeError:
                # Pass while the process_info file is being written to
                pass

        transfer_process_data = process_data['resource_transfer_in']

        # If transfer is still in progress then cancel the subprocess
        if transfer_process_data['status'] == 'in_progress':
            for process in multiprocessing.active_children():
                if process.pid == transfer_process_data['function_process_id']:
                    process.kill()
                    process.join()
                    transfer_process_data['status'] = 'failed'
                    transfer_process_data[
                        'message'] = 'Transfer was cancelled by the user'
                    transfer_process_data['status_code'] = '499'
                    transfer_process_data['expiration'] = str(timezone.now() +
                                                              relativedelta(
                                                                  hours=1))
                    update_or_create_process_info(transfer_process_data,
                                                  'resource_transfer_in',
                                                  self.ticket_number)
                    return Response(data={
                        'status_code':
                        transfer_process_data['status_code'],
                        'message':
                        transfer_process_data['message']
                    },
                                    status=status.HTTP_200_OK)
        # If transfer is finished then don't attempt to cancel subprocess
        else:
            return Response(data={
                'status_code': transfer_process_data['status_code'],
                'message': transfer_process_data['message']
            },
                            status=status.HTTP_406_NOT_ACCEPTABLE)
Exemplo n.º 3
0
    def get(self, request, ticket_number):
        """
        Check in on the resource's transfer process state.

        Parameters
        ----------
        ticket_number : str
            The ticket number of the transfer being prepared.

        Returns
        -------
        200: OK
        """
        # Perform token validation. Read data from the process_info file.
        try:
            destination_token = get_destination_token(request)
            source_token = get_source_token(request)
            process_data = get_process_info_data('transfers', ticket_number)
            process_token_validation(hash_tokens(destination_token),
                                     process_data, 'presqt-destination-token')
            process_token_validation(hash_tokens(source_token), process_data, 'presqt-source-token')
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        transfer_status = process_data['status']
        data = {'status_code': process_data['status_code'], 'message': process_data['message']}

        if transfer_status == 'finished':
            http_status = status.HTTP_200_OK
            data['failed_fixity'] = process_data['failed_fixity']
            data['resources_ignored'] = process_data['resources_ignored']
            data['resources_updated'] = process_data['resources_updated']
        else:
            if transfer_status == 'in_progress':
                http_status = status.HTTP_202_ACCEPTED
            else:
                http_status = status.HTTP_500_INTERNAL_SERVER_ERROR

        return Response(status=http_status, data=data)
Exemplo n.º 4
0
    def transfer_post(self):
        """
        Transfer resources to a specific existing target resource or create a new target resource.

        Returns
        -------
        Response object in JSON format
        """
        try:
            self.destination_token = get_destination_token(self.request)
            self.source_token = get_source_token(self.request)
            self.email = get_user_email_opt(self.request)
            self.file_duplicate_action = file_duplicate_action_validation(
                self.request)
            self.keyword_action = keyword_action_validation(self.request)
            self.fairshare_evaluator_action = fairshare_evaluator_validation(
                self.request)
            self.source_target_name, self.source_resource_id, self.keywords = transfer_post_body_validation(
                self.request)
            target_valid, self.infinite_depth = target_validation(
                self.destination_target_name, self.action)
            target_validation(self.source_target_name, 'resource_transfer_out')
            transfer_target_validation(self.source_target_name,
                                       self.destination_target_name)
            self.supports_keywords = get_keyword_support(
                self.source_target_name, self.destination_target_name)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Generate ticket number
        self.ticket_number = '{}_{}'.format(
            hash_tokens(self.source_token),
            hash_tokens(self.destination_token))
        ticket_path = os.path.join("mediafiles", "jobs",
                                   str(self.ticket_number))

        self.ticket_path = os.path.join('mediafiles', 'jobs',
                                        str(self.ticket_number), 'transfer')

        # Create directory and process_info json file
        self.process_info_obj = {
            'presqt-source-token': hash_tokens(self.source_token),
            'presqt-destination-token': hash_tokens(self.destination_token),
            'status': 'in_progress',
            'expiration': str(timezone.now() + relativedelta(hours=5)),
            'message': 'Transfer is being processed on the server',
            'download_status': None,
            'upload_status': None,
            'status_code': None,
            'function_process_id': None,
            'upload_total_files': 0,
            'upload_files_finished': 0,
            'download_total_files': 0,
            'download_files_finished': 0
        }
        self.process_info_path = update_or_create_process_info(
            self.process_info_obj, self.action, self.ticket_number)

        self.base_directory_name = '{}_{}_transfer_{}'.format(
            self.source_target_name, self.destination_target_name,
            self.source_resource_id)

        # Remove any resources that already exist in this user's job directory
        if os.path.exists(self.ticket_path):
            for folder in next(os.walk(self.ticket_path))[1]:
                shutil.rmtree(os.path.join(self.ticket_path, folder))

        # Spawn the transfer_resource method separate from the request server by using multiprocess.
        spawn_action_process(self, self._transfer_resource, self.action)

        reversed_url = reverse('job_status', kwargs={'action': 'transfer'})
        transfer_hyperlink = self.request.build_absolute_uri(reversed_url)

        return Response(status=status.HTTP_202_ACCEPTED,
                        data={
                            'message': 'The server is processing the request.',
                            'transfer_job': transfer_hyperlink
                        })
Exemplo n.º 5
0
    def get(self, request, target_name):
        """
        Retrieve all Resources.

        Parameters
        ----------
        target_name : str
            The string name of the Target resource to retrieve.

        Returns
        -------
        200 : OK
        A list-like JSON representation of all resources for the given Target and token.
        [
            {
                "kind": "container",
                "kind_name": "folder",
                "id": "5cd9832cf244ec0021e5f245",
                "container": "cmn5z:osfstorage",
                "title": "Images",
                "links": [
                    {
                        "name": "Detail",
                        "link": "https://localhost/api_v1/targets/osf/resources/5cd9832cf244ec0021e5f245/",
                        "method": "GET"
                    }
                ]
            },
            {
                "kind": "item",
                "kind_name": "file",
                "id": "5cd98510f244ec001fe5632f",
                "container": "5cd9832cf244ec0021e5f245",
                "title": "22776439564_7edbed7e10_o.jpg",
                "links": [
                    {
                        "name": "Detail",
                        "link": "https://localhost/api_v1/targets/osf/resources/5cd98510f244ec001fe5632f/",
                        "method": "GET"
                    }
                ]
            }
        ]

        400: Bad Request
        {
            "error": "PresQT Error: 'new_target' does not support the action 'resource_collection'."
        }
        or
        {
            "error": "PresQT Error: 'presqt-source-token' missing in the request headers."
        }
        or
        {
            "error": "PresQT Error: The search query is not formatted correctly."
        }

        401: Unauthorized
        {
            "error": "Token is invalid. Response returned a 401 status code.""
        }

        404: Not Found
        {
            "error": "PresQT Error: 'bad_target' is not a valid Target name."
        }
        """
        action = 'resource_collection'

        # Perform token, target, and action validation
        try:
            token = get_source_token(request)
            target_validation(target_name, action)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        query_params = request.query_params
        # Validate the search query if there is one.
        if query_params != {}:
            try:
                search_validator(query_params)
                query_params_value = list(query_params.values())[0]
                if query_params_value.isspace() or query_params_value == '':
                    # If title is empty, we want to only return user resources.
                    query_params = {}
            except PresQTResponseException as e:
                # Catch any errors that happen within the search validation
                return Response(data={'error': e.data}, status=e.status_code)
        # Fetch the proper function to call
        func = FunctionRouter.get_function(target_name, action)

        # Fetch the target's resources
        try:
            resources = func(token, query_params)
        except PresQTResponseException as e:
            # Catch any errors that happen within the target fetch
            return Response(data={'error': e.data}, status=e.status_code)

        serializer = ResourcesSerializer(instance=resources, many=True, context={
                                         'target_name': target_name,
                                         'request': request})

        return Response(serializer.data)
Exemplo n.º 6
0
    def patch(self, request, ticket_number):
        """
        Cancel the resource transfer process on the server. Update the process_info.json
        file appropriately.

        Parameters
        ----------
        ticket_number : str
            The ticket number of the transfer being prepared.

        Returns
        -------
        200: OK
        {
            "status_code": "499",
            "message": "Transfer was cancelled by the user"
        }

        400: Bad Request
        {
            "error": "PresQT Error: 'presqt-destination-token' missing in the request headers."
        }

        400: Bad Request
        {
            "error": "PresQT Error: 'presqt-source-token' missing in the request headers."
        }

        401: Unauthorized
        {
            "error": "PresQT Error: Header 'presqt-destination-token' does not match the
            'presqt-destination-token' for this server process."
        }

        401: Unauthorized
        {
            "error": "PresQT Error: Header 'presqt-source-token' does not match the
            'presqt-source-token' for this server process."
        }

        404: Not Found
        {
            "error": "PresQT Error: Invalid ticket number, '1234'."
        }

        406: Not Acceptable
        {
            "status_code": "200",
            "message": "Transfer Successful"
        }
        """
        # Perform token validation. Read data from the process_info file.
        try:
            token = get_destination_token(request)
            source_token = get_source_token(request)
            process_data = get_process_info_data('transfers', ticket_number)
            process_token_validation(hash_tokens(token), process_data, 'presqt-destination-token')
            process_token_validation(hash_tokens(source_token), process_data, 'presqt-source-token')
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Wait until the spawned off process has started to cancel the transfer
        while process_data['function_process_id'] is None:
            try:
                process_data = get_process_info_data('transfers', ticket_number)
            except json.decoder.JSONDecodeError:
                # Pass while the process_info file is being written to
                pass

        # If transfer is still in progress then cancel the subprocess
        if process_data['status'] == 'in_progress':
            for process in multiprocessing.active_children():
                if process.pid == process_data['function_process_id']:
                    process.kill()
                    process.join()
                    process_data['status'] = 'failed'
                    process_data['message'] = 'Transfer was cancelled by the user'
                    process_data['status_code'] = '499'
                    process_data['expiration'] = str(timezone.now() + relativedelta(hours=1))
                    process_info_path = 'mediafiles/transfers/{}/process_info.json'.format(
                        ticket_number)
                    write_file(process_info_path, process_data, True)

                    return Response(
                        data={'status_code': process_data['status_code'], 'message': process_data['message']},
                        status=status.HTTP_200_OK)
        # If transfer is finished then don't attempt to cancel subprocess
        else:
            return Response(
                data={'status_code': process_data['status_code'], 'message': process_data['message']},
                status=status.HTTP_406_NOT_ACCEPTABLE)
Exemplo n.º 7
0
    def get(self, request, ticket_number, response_format=None):
        """
        Check in on the resource's download process state.

        Parameters
        ----------
        ticket_number : str
            The ticket number of the download being prepared.
        response_format: str
            The type of response to return. Either json or zip

        Returns
        -------
        200: OK
        Returns the zip of resources to be downloaded.
        or
        {
            "status_code": "200",
            "message": "Download successful but with fixity errors.",
            "failed_fixity": ["/Character Sheet - Alternative - Print Version.pdf"]
        }

        202: Accepted
        {
            "status_code": null,
            "message": "Download is being processed on the server"
        }

        400: Bad Request
        {
            "error": "PresQT Error: 'presqt-source-token' missing in the request headers."
        }
        or
        {
            "error": "PresQT Error: 'csv' is not a valid format for this endpoint."
        }

        401: Unauthorized
        {
            "error": "PresQT Error: Header 'presqt-source-token' does not match the
            'presqt-source-token' for this server process."
        }

        404: Not Found
        {
            "error": "PresQT Error: Invalid ticket number, '1234'."
        }

        500: Internal Server Error
        {
            "status_code": "404",
            "message": "Resource with id 'bad_id' not found for this user."
        }
        """
        # Perform token validation. Read data from the process_info file.
        try:
            token = get_source_token(request)
            data = get_process_info_data('downloads', ticket_number)
            process_token_validation(hash_tokens(token), data,
                                     'presqt-source-token')
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Verify that the only acceptable response format was provided
        if response_format and response_format not in ['json', 'zip']:
            return Response(data={
                'error':
                'PresQT Error: {} is not a valid format for this endpoint.'.
                format(response_format)
            },
                            status=status.HTTP_400_BAD_REQUEST)

        download_status = data['status']
        message = data['message']
        status_code = data['status_code']

        # Return the file to download if it has finished.
        if download_status == 'finished':
            if response_format == 'zip':
                # Path to the file to be downloaded
                zip_name = data['zip_name']
                zip_file_path = os.path.join('mediafiles', 'downloads',
                                             ticket_number, zip_name)

                response = HttpResponse(open(zip_file_path, 'rb'),
                                        content_type='application/zip')
                response[
                    'Content-Disposition'] = 'attachment; filename={}'.format(
                        zip_name)
            else:
                response = Response(data={
                    'status_code': status_code,
                    'message': message,
                    'zip_name': data['zip_name'],
                    'failed_fixity': data['failed_fixity']
                },
                                    status=status.HTTP_200_OK)
            return response
        else:
            if download_status == 'in_progress':
                http_status = status.HTTP_202_ACCEPTED
            else:
                http_status = status.HTTP_500_INTERNAL_SERVER_ERROR

            return Response(status=http_status,
                            data={
                                'status_code': status_code,
                                'message': message
                            })
Exemplo n.º 8
0
    def patch(self, request, ticket_number, response_format=None):
        """
        Cancel the resource download process on the server. Update the process_info.json
        file appropriately.

        Parameters
        ----------
        ticket_number : str
            The ticket number of the download being prepared.
        response_format: str
            For patch, response_format should be JSON or None

        Returns
        -------
        200: OK
        {
            "status_code": "499",
            "message": "Download was cancelled by the user"
        }

        400: Bad Request
        {
            "error": "PresQT Error: 'presqt-source-token' missing in the request headers."
        }
        or
        {
            "error": "PresQT Error: 'zip' is not a valid format for this endpoint."
        }


        401: Unauthorized
        {
            "error": "PresQT Error: Header 'presqt-source-token' does not match the
            'presqt-source-token' for this server process."
        }

        404: Not Found
        {
            "error": "PresQT Error: Invalid ticket number, '1234'."
        }

        406: Not Acceptable
        {
            "status_code": "200",
            "message": "Download Successful"
        }
        """
        # Perform token validation. Read data from the process_info file.
        try:
            token = get_source_token(request)
            data = get_process_info_data('downloads', ticket_number)
            process_token_validation(hash_tokens(token), data,
                                     'presqt-source-token')
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Verify that the only acceptable response format was provided
        if response_format and response_format != 'json':
            return Response(data={
                'error':
                'PresQT Error: {} is not a valid format for this endpoint.'.
                format(response_format)
            },
                            status=status.HTTP_400_BAD_REQUEST)

        # Wait until the spawned off process has started to cancel the download
        while data['function_process_id'] is None:
            try:
                data = get_process_info_data('downloads', ticket_number)
            except json.decoder.JSONDecodeError:
                # Pass while the process_info file is being written to
                pass

        # If download is still in progress then cancel the subprocess
        if data['status'] == 'in_progress':
            for process in multiprocessing.active_children():
                if process.pid == data['function_process_id']:
                    process.kill()
                    process.join()
                    data['status'] = 'failed'
                    data['message'] = 'Download was cancelled by the user'
                    data['status_code'] = '499'
                    data['expiration'] = str(timezone.now() +
                                             relativedelta(hours=1))
                    process_info_path = 'mediafiles/downloads/{}/process_info.json'.format(
                        ticket_number)
                    write_file(process_info_path, data, True)

                    return Response(data={
                        'status_code': data['status_code'],
                        'message': data['message']
                    },
                                    status=status.HTTP_200_OK)
        # If download is finished then don't attempt to cancel subprocess
        else:
            return Response(data={
                'status_code': data['status_code'],
                'message': data['message']
            },
                            status=status.HTTP_406_NOT_ACCEPTABLE)
Exemplo n.º 9
0
    def post(self, request):
        """
        Upload a proposal task to EaaSI

        Returns
        -------
        200: OK
        {
            "id": "19",
            "message": "Proposal task was submitted."
            "proposal_link": "https://localhost/api_v1/services/eaasi/1/"
        }

        400: Bad Request
        {
            "error": "PresQT Error: 'presqt-source-token' missing in the request headers."
        }
        or
        {
            "error": "PresQT Error: A download does not exist for this user on the server."
        }

        404: Not Found
        {
            "error": "PresQT Error: Invalid ticket number, '1234'."
        }
        or
        {
            "error": "PresQT Error: A resource_download does not exist for this user on the server."
        }
        """
        # Get the source token from the request, hash it to get the ticket_number, get the
        # process_info.json file connected with the ticket_number.
        try:
            source_token = get_source_token(self.request)
            ticket_number = hash_tokens(source_token)
            process_info_data = get_process_info_data(ticket_number)
            download_data = get_process_info_action(process_info_data,
                                                    'resource_download')
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Create a one time use token for EaaSI to use.
        eaasi_token = str(uuid4())
        download_data['eaasi_token'] = eaasi_token
        write_file(
            'mediafiles/jobs/{}/process_info.json'.format(ticket_number),
            process_info_data, True)

        # Build EaaSI download endpoint url
        eaasi_download_reverse = reverse(
            'eaasi_download', kwargs={"ticket_number": ticket_number})
        eaasi_download_url = request.build_absolute_uri(eaasi_download_reverse)
        final_eaasi_download_url = '{}?eaasi_token={}'.format(
            eaasi_download_url, eaasi_token)

        data = {"data_url": final_eaasi_download_url, "data_type": "bagit+zip"}

        response = requests.post(
            'https://eaasi-portal.emulation.cloud/environment-proposer/api/v1/proposals',
            data=json.dumps(data),
            headers={"Content-Type": "application/json"})

        if response.status_code != 202:
            return Response(data={
                'message':
                'Proposal submission returned a status code of {}.'.format(
                    response.status_code)
            },
                            status=response.status_code)

        response_json = response.json()

        # Add Proposal link to payload
        reverse_proposal_url = reverse(
            'proposal', kwargs={"proposal_id": response_json['id']})
        response_json['proposal_link'] = request.build_absolute_uri(
            reverse_proposal_url)

        return Response(data=response_json, status=status.HTTP_200_OK)
Exemplo n.º 10
0
    def download_get(self):
        """
        Get the status of a download job.

        Will return either a json object or a file bytes depending on the 'resource_format' url
        parameter
        """
        if self.request.query_params:
            try:
                # This check will run for the email links we generate
                self.ticket_number = self.request.query_params['ticket_number']
                self.process_data = get_process_info_data(self.ticket_number)
            except (MultiValueDictKeyError, PresQTValidationError):
                return Response(data={
                    'error':
                    "'ticket_number' not found as query parameter or invalid 'ticket_number' provided."
                },
                                status=status.HTTP_400_BAD_REQUEST)
        else:
            # Perform token validation. Read data from the process_info file.
            try:
                source_token = get_source_token(self.request)
                self.ticket_number = hash_tokens(source_token)
                self.process_data = get_process_info_data(self.ticket_number)
            except PresQTValidationError as e:
                return Response(data={'error': e.data}, status=e.status_code)

        # Verify that the only acceptable response format was provided.
        if self.response_format and self.response_format not in [
                'json', 'zip'
        ]:
            return Response(data={
                'error':
                'PresQT Error: {} is not a valid format for this endpoint.'.
                format(self.response_format)
            },
                            status=status.HTTP_400_BAD_REQUEST)
        try:
            download_process_data = self.process_data['resource_download']
        except KeyError:
            return Response(data={
                'error':
                'PresQT Error: "resource_download" not found in process_info file.'
            },
                            status=status.HTTP_400_BAD_REQUEST)

        download_status = download_process_data['status']
        message = download_process_data['message']
        status_code = download_process_data['status_code']

        total_files = download_process_data['download_total_files']
        files_finished = download_process_data['download_files_finished']
        download_job_percentage = calculate_job_percentage(
            total_files, files_finished)

        # Return the file to download if it has finished.
        if download_status == 'finished':
            if self.response_format == 'zip':
                # Path to the file to be downloaded
                zip_name = download_process_data['zip_name']
                zip_file_path = os.path.join('mediafiles', 'jobs',
                                             self.ticket_number, 'download',
                                             zip_name)

                response = HttpResponse(open(zip_file_path, 'rb'),
                                        content_type='application/zip')
                response[
                    'Content-Disposition'] = 'attachment; filename={}'.format(
                        zip_name)
            else:
                response = Response(data={
                    'status_code':
                    status_code,
                    'message':
                    message,
                    'zip_name':
                    download_process_data['zip_name'],
                    'failed_fixity':
                    download_process_data['failed_fixity'],
                    'job_percentage':
                    download_job_percentage,
                    'status':
                    download_status
                },
                                    status=status.HTTP_200_OK)
            return response
        else:
            if download_status == 'in_progress':
                http_status = status.HTTP_202_ACCEPTED
            else:
                http_status = status.HTTP_500_INTERNAL_SERVER_ERROR

            return Response(status=http_status,
                            data={
                                'job_percentage': download_job_percentage,
                                'status': download_status,
                                'status_code': status_code,
                                'message': message
                            })
Exemplo n.º 11
0
    def download_patch(self):
        """
        Attempt to cancel a download job.
        """
        # Perform token validation. Read data from the process_info file.
        try:
            source_token = get_source_token(self.request)
            self.ticket_number = hash_tokens(source_token)
            self.process_data = get_process_info_data(self.ticket_number)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Verify that the only acceptable response format was provided
        if self.response_format and self.response_format != 'json':
            return Response(data={
                'error':
                'PresQT Error: {} is not a valid format for this endpoint.'.
                format(self.response_format)
            },
                            status=status.HTTP_400_BAD_REQUEST)

        # Wait until the spawned off process has started to cancel the download
        while self.process_data['resource_download'][
                'function_process_id'] is None:
            try:
                self.process_data = get_process_info_data(self.ticket_number)
            except json.decoder.JSONDecodeError:
                # Pass while the process_info file is being written to
                pass

        download_process_data = self.process_data['resource_download']

        # If download is still in progress then cancel the subprocess
        if download_process_data['status'] == 'in_progress':
            for process in multiprocessing.active_children():
                if process.pid == download_process_data['function_process_id']:
                    process.kill()
                    process.join()
                    download_process_data['status'] = 'failed'
                    download_process_data[
                        'message'] = 'Download was cancelled by the user'
                    download_process_data['status_code'] = '499'
                    download_process_data['expiration'] = str(timezone.now() +
                                                              relativedelta(
                                                                  hours=1))
                    update_or_create_process_info(download_process_data,
                                                  'resource_download',
                                                  self.ticket_number)

                return Response(data={
                    'status_code':
                    download_process_data['status_code'],
                    'message':
                    download_process_data['message']
                },
                                status=status.HTTP_200_OK)
        # If download is finished then don't attempt to cancel subprocess
        else:
            return Response(data={
                'status_code': download_process_data['status_code'],
                'message': download_process_data['message']
            },
                            status=status.HTTP_406_NOT_ACCEPTABLE)
Exemplo n.º 12
0
    def transfer_get(self):
        """
        Get the status of a transfer job.
        """
        # Perform token validation. Read data from the process_info file.
        try:
            destination_token = get_destination_token(self.request)
            source_token = get_source_token(self.request)
            self.ticket_number = '{}_{}'.format(hash_tokens(source_token),
                                                hash_tokens(destination_token))
            self.process_data = get_process_info_data(self.ticket_number)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        try:
            transfer_process_data = self.process_data['resource_transfer_in']
        except KeyError:
            return Response(data={
                'error':
                'PresQT Error: "resource_download" not found in process_info file.'
            },
                            status=status.HTTP_400_BAD_REQUEST)

        transfer_status = transfer_process_data['status']
        upload_job_percentage = calculate_job_percentage(
            transfer_process_data['upload_total_files'],
            transfer_process_data['upload_files_finished'])
        download_job_percentage = calculate_job_percentage(
            transfer_process_data['download_total_files'],
            transfer_process_data['download_files_finished'])
        data = {
            'status_code':
            transfer_process_data['status_code'],
            'status':
            transfer_status,
            'message':
            transfer_process_data['message'],
            'job_percentage':
            round((upload_job_percentage + download_job_percentage) / 2),
        }

        if transfer_status == 'finished':
            http_status = status.HTTP_200_OK
            data['failed_fixity'] = transfer_process_data['failed_fixity']
            data['resources_ignored'] = transfer_process_data[
                'resources_ignored']
            data['resources_updated'] = transfer_process_data[
                'resources_updated']
            data['enhanced_keywords'] = transfer_process_data[
                'enhanced_keywords']
            data['initial_keywords'] = transfer_process_data[
                'initial_keywords']
            data['source_resource_id'] = transfer_process_data[
                'source_resource_id']
            data['destination_resource_id'] = transfer_process_data[
                'destination_resource_id']
            data['fairshare_evaluation_results'] = transfer_process_data[
                'fairshare_evaluation_results']
            data['link_to_resource'] = transfer_process_data[
                'link_to_resource']
            data['job_percentage'] = 99
        else:
            if transfer_status == 'in_progress':
                http_status = status.HTTP_202_ACCEPTED
            else:
                http_status = status.HTTP_500_INTERNAL_SERVER_ERROR

        return Response(status=http_status, data=data)
Exemplo n.º 13
0
    def transfer_post(self):
        """
        Transfer resources to a specific existing target resource or create a new target resource.

        Returns
        -------
        Response object in JSON format
        """
        try:
            self.destination_token = get_destination_token(self.request)
            self.source_token = get_source_token(self.request)
            self.file_duplicate_action = file_duplicate_action_validation(
                self.request)
            self.source_target_name, self.source_resource_id = transfer_post_body_validation(
                self.request)
            target_valid, self.infinite_depth = target_validation(
                self.destination_target_name, self.action)
            target_validation(self.source_target_name, 'resource_transfer_out')
            transfer_target_validation(self.source_target_name,
                                       self.destination_target_name)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Generate ticket number
        ticket_number = uuid4()
        self.ticket_path = os.path.join("mediafiles", "transfers",
                                        str(ticket_number))

        # Create directory and process_info json file
        self.process_info_obj = {
            'presqt-source-token': hash_tokens(self.source_token),
            'presqt-destination-token': hash_tokens(self.destination_token),
            'status': 'in_progress',
            'expiration': str(timezone.now() + relativedelta(days=5)),
            'message': 'Transfer is being processed on the server',
            'download_status': None,
            'upload_status': None,
            'status_code': None,
            'function_process_id': None
        }
        self.process_info_path = os.path.join(self.ticket_path,
                                              "process_info.json")
        write_file(self.process_info_path, self.process_info_obj, True)

        self.base_directory_name = '{}_{}_transfer_{}'.format(
            self.source_target_name, self.destination_target_name,
            self.source_resource_id)

        # Spawn the transfer_resource method separate from the request server by using multiprocess.
        spawn_action_process(self, self._transfer_resource)

        reversed_url = reverse('transfer_job',
                               kwargs={'ticket_number': ticket_number})
        transfer_hyperlink = self.request.build_absolute_uri(reversed_url)

        return Response(status=status.HTTP_202_ACCEPTED,
                        data={
                            'ticket_number': ticket_number,
                            'message': 'The server is processing the request.',
                            'transfer_job': transfer_hyperlink
                        })
Exemplo n.º 14
0
    def get_zip_format(self):
        """
        Prepares a download of a resource with the given resource ID provided. Spawns a process
        separate from the request server to do the actual downloading and zip-file preparation.

        Returns
        -------
        Response object with ticket information.
        """
        # Perform token, target, and action validation
        try:
            self.source_token = get_source_token(self.request)
            target_validation(self.source_target_name, self.action)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Generate ticket number
        ticket_number = uuid4()
        self.ticket_path = os.path.join('mediafiles', 'downloads',
                                        str(ticket_number))

        # Create directory and process_info json file
        self.process_info_obj = {
            'presqt-source-token': hash_tokens(self.source_token),
            'status': 'in_progress',
            'expiration': str(timezone.now() + relativedelta(days=5)),
            'message': 'Download is being processed on the server',
            'status_code': None,
            'function_process_id': None
        }

        self.process_info_path = os.path.join(str(self.ticket_path),
                                              'process_info.json')
        write_file(self.process_info_path, self.process_info_obj, True)

        self.base_directory_name = '{}_download_{}'.format(
            self.source_target_name, self.source_resource_id)
        # Spawn the upload_resource method separate from the request server by using multiprocess.
        spawn_action_process(self, self._download_resource)

        # Get the download url for zip format
        reversed_url = reverse('download_job',
                               kwargs={
                                   'ticket_number': ticket_number,
                                   'response_format': 'zip'
                               })
        download_zip_hyperlink = self.request.build_absolute_uri(reversed_url)

        # Get the download url for json format
        reversed_url = reverse('download_job',
                               kwargs={
                                   'ticket_number': ticket_number,
                                   'response_format': 'json'
                               })
        download_json_hyperlink = self.request.build_absolute_uri(reversed_url)

        return Response(status=status.HTTP_202_ACCEPTED,
                        data={
                            'ticket_number': ticket_number,
                            'message': 'The server is processing the request.',
                            'download_job_zip': download_zip_hyperlink,
                            'download_job_json': download_json_hyperlink
                        })
Exemplo n.º 15
0
    def get(self, request, target_name, resource_id):
        """
        Retrieve all keywords of a given resource.

        Parameters
        ----------
        target_name : str
            The string name of the Target resource to retrieve.
        resource_id : str
             The id of the Resource to retrieve.

        Returns
        -------
        200 : OK
        A dictionary containing the keywords of the resource.
        {
            "keywords": [
                "eggs",
                "animal",
                "water"
            ],
            "enhanced_keywords": [
                "animals",
                "Animals",
                "eggs",
                "EGG",
                "Electrostatic Gravity Gradiometer",
                "water",
                "Water",
                "DISORDERED SOLVENT",
                "aqua",
                "Wasser",
                "dihydrogen oxide",
                "OXYGEN ATOM",
                "oxidane",
                "water"
            ]
        }

        400: Bad Request
        {
            "error": "{Target} {Resource Type} do not have keywords."
        }
        or
        {
            "error": "PresQT Error: 'new_target' does not support the action 'keywords'."
        }

        401: Unauthorized
        {
            "error": "Token is invalid. Response returned a 401 status code.""
        }
        """
        action = 'keywords'

        try:
            token = get_source_token(request)
            target_validation(target_name, action)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Fetch the proper function to call
        func = FunctionRouter.get_function(target_name, action)

        # Fetch the resource keywords
        try:
            # Will return a dictionary with resource's keywords
            keywords = func(token, resource_id)
        except PresQTResponseException as e:
            # Catch any errors that happen
            return Response(data={'error': e.data}, status=e.status_code)

        # Call function which calls SciGraph for keyword suggestions.
        try:
            # Return a new keyword list and a final list.
            new_list_of_keywords, final_list_of_keywords = keyword_enhancer(
                keywords['keywords'])
        except PresQTResponseException as e:
            # Catch any errors that happen within the target fetch
            return Response(data={'error': e.data}, status=e.status_code)

        return Response(data={
            "keywords": keywords['keywords'],
            "enhanced_keywords": new_list_of_keywords,
            "all_keywords": final_list_of_keywords
        },
                        status=status.HTTP_200_OK)
Exemplo n.º 16
0
    def post(self, request, target_name, resource_id):
        """
        Upload suggested keywords to a given resource.

        Parameters
        ----------
        target_name : str
            The string name of the Target resource to retrieve.
        resource_id : str
             The id of the Resource to retrieve.

        Returns
        -------
        202 : ACCEPTED
        A dictionary containing the keywords of the resource.
        {
            "keywords_added": [
                "Animals",
                "aqua",
                "dihydrogen oxide",
                "DISORDERED SOLVENT",
                "EGG",
                "Electrostatic Gravity Gradiometer",
                "oxidane",
                "OXYGEN ATOM",
                "Wasser",
                "Water"
            ],
            "final_keywords": [
                "animal",
                "Animals",
                "aqua",
                "dihydrogen oxide",
                "DISORDERED SOLVENT",
                "EGG",
                "eggs",
                "Electrostatic Gravity Gradiometer",
                "oxidane",
                "OXYGEN ATOM",
                "Wasser",
                "water",
                "Water"
            ]
        }

        400: Bad Request
        {
            "error": "{Target} {Resource Type} do not have keywords."
        }
        or
        {
            "error": "PresQT Error: 'new_target' does not support the action 'keywords'."
        }
        or
        {
            "error": "PresQT Error: 'new_target' does not support the action 'keywords_upload'."
        }
        or
        {
            "error": "PresQT Error: keywords is missing from the request body."
        }
        or
        {
            "error": "PresQT Error: keywords must be in list format."
        }

        401: Unauthorized
        {
            "error": "Token is invalid. Response returned a 401 status code.""
        }

        500: Internal Server Error
        {
            "error": "PresQT Error: Error updating the PresQT metadata file on {Target}. Keywords have been added successfully."
        }

        Target Error
        {
            "error": "{Target} returned a {status_code} error trying to update keywords.
        }
        """
        action = "keywords_upload"

        try:
            token = get_source_token(request)
            target_validation(target_name, action)
            target_validation(target_name, 'keywords')
            keywords = keyword_post_validation(request)
        except PresQTValidationError as e:
            return Response(data={'error': e.data}, status=e.status_code)

        # Fetch the initial keyword function
        func = FunctionRouter.get_function(target_name, 'keywords')

        # Fetch the resource keywords
        try:
            # Will return a dictionary with resource's keywords
            initial_keywords = func(token, resource_id)
        except PresQTResponseException as e:
            # Catch any errors that happen
            return Response(data={'error': e.data}, status=e.status_code)

        # Add the keywords
        all_keywords = initial_keywords['keywords'] + keywords

        # Fetch the update keywords function
        func = FunctionRouter.get_function(target_name, action)

        # Function will upload new keywords to the selected resource
        try:
            # Will return a dictionary with the updated_keywords
            updated_keywords = func(token, resource_id, all_keywords)
        except PresQTResponseException as e:
            # Catch any errors that happen within the target fetch
            return Response(data={'error': e.data}, status=e.status_code)

        # Get ontologies for enhanced keywords
        ontologies = fetch_ontologies(keywords)

        # Build the metadata dictionary for this action.
        source_target_data = get_target_data(target_name)
        metadata_dict = {
            "allKeywords":
            updated_keywords['updated_keywords'],
            "actions": [{
                'id':
                str(uuid4()),
                'details':
                'PresQT Enhance Keywords in {}'.format(
                    source_target_data['readable_name']),
                'actionDateTime':
                str(timezone.now()),
                'actionType':
                'keyword_enhancement',
                'sourceTargetName':
                target_name,
                'destinationTargetName':
                target_name,
                'sourceUsername':
                '******',
                'destinationUsername':
                '******',
                'keywords': {
                    'sourceKeywordsAdded': [],
                    'sourceKeywordsEnhanced': keywords,
                    'ontologies': ontologies,
                    'enhancer': 'scigraph'
                },
                'files': {
                    'created': [],
                    'updated': [],
                    'ignored': []
                }
            }]
        }

        # Update the metadata file, or create a new one.
        metadata_func = FunctionRouter.get_function(target_name,
                                                    'metadata_upload')
        try:
            metadata_func(token, updated_keywords['project_id'], metadata_dict)
        except PresQTError:
            # Catch any errors that happen within the target fetch
            return Response(data={
                'error':
                "PresQT Error: Error updating the PresQT metadata file on {}. Keywords have been added successfully."
                .format(target_name)
            },
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response(data={
            'initial_keywords': initial_keywords,
            'keywords_added': keywords,
            'final_keywords': updated_keywords['updated_keywords']
        },
                        status=status.HTTP_202_ACCEPTED)