Esempio n. 1
0
def request_withdrawal(method: str, params: MultiDict, session: Session,
                       submission_id: int, **kwargs) -> Response:
    """Request withdrawal of a paper."""
    submitter, client = user_and_client_from_session(session)
    logger.debug(f'method: {method}, submission: {submission_id}. {params}')

    # Will raise NotFound if there is no such submission.
    submission, _ = load_submission(submission_id)

    # The submission must be announced for this to be a withdrawal request.
    if not submission.is_announced:
        alerts.flash_failure(
            Markup(
                "Submission must first be announced. See "
                "<a href='https://arxiv.org/help/withdraw'>the arXiv help pages"
                "</a> for details."))
        loc = url_for('ui.create_submission')
        return {}, status.SEE_OTHER, {'Location': loc}

    # The form should be prepopulated based on the current state of the
    # submission.
    if method == 'GET':
        params = MultiDict({})

    params.setdefault("confirmed", False)
    form = WithdrawalForm(params)
    response_data = {
        'submission_id': submission_id,
        'submission': submission,
        'form': form,
    }

    if method == 'POST':
        # We require the user to confirm that they wish to proceed.
        if not form.validate():
            raise BadRequest(response_data)

        cmd = RequestWithdrawal(reason=form.withdrawal_reason.data,
                                creator=submitter,
                                client=client)
        if not validate_command(form, cmd, submission, 'withdrawal_reason'):
            raise BadRequest(response_data)

        if not form.confirmed.data:
            response_data['require_confirmation'] = True
            return response_data, status.OK, {}

        response_data['require_confirmation'] = True
        try:
            # Save the events created during form validation.
            submission, _ = save(cmd, submission_id=submission_id)
        except SaveError as e:
            raise InternalServerError(response_data) from e

        # Success! Send user back to the submission page.
        alerts.flash_success("Withdrawal request submitted.")
        status_url = url_for('ui.create_submission')
        return {}, status.SEE_OTHER, {'Location': status_url}
    logger.debug('Nothing to do, return 200')
    return response_data, status.OK, {}
Esempio n. 2
0
def start_compilation(params: MultiDict, session: Session, submission_id: int,
                      token: str, **kwargs) -> Response:
    submitter, client = user_and_client_from_session(session)
    submission, submission_events = load_submission(submission_id)
    form = CompilationForm(params)
    response_data = {
        'submission_id': submission_id,
        'submission': submission,
        'form': form,
        'status': None,
        'must_process': _must_process(submission)
    }

    # Create label and link for PS/PDF stamp/watermark.
    #
    # Stamp format for submission is of form [identifier category date]
    #
    # "arXiv:submit/<submission_id>  [<primary category>] DD MON YYYY
    #
    # Date segment is optional and added automatically by converter.
    #
    stamp_label = f'arXiv:submit/{submission_id}'

    if submission.primary_classification \
                and submission.primary_classification.category:
        # Create stamp label string - for now we'll let converter
        #                             add date segment to stamp label
        primary_category = submission.primary_classification.category
        stamp_label = stamp_label + f'  [{primary_category}]'

    stamp_link = f'/{submission_id}/preview.pdf'

    if not form.validate():
        raise BadRequest(response_data)
    try:
        logger.debug('Start compilation for %s (identifier) %s (checksum)',
                     submission.source_content.identifier,
                     submission.source_content.checksum)
        stat = Compiler.compile(submission.source_content.identifier,
                                submission.source_content.checksum, token,
                                stamp_label, stamp_link)
    except exceptions.RequestFailed as e:
        alerts.flash_failure(f"We couldn't compile your submission. {SUPPORT}",
                             title="Compilation failed")
        logger.error('Error while requesting compilation for %s: %s',
                     submission_id, e)
        raise InternalServerError(response_data) from e

    response_data['status'] = stat
    if stat.status is Compilation.Status.FAILED:
        alerts.flash_failure(f"Compilation failed")
    else:
        alerts.flash_success(
            "We are compiling your submission. This may take a minute or two."
            " This page will refresh automatically every 5 seconds. You can "
            " also refresh this page manually to check the current status. ",
            title="Compilation started"
        )
    redirect = url_for('ui.file_process', submission_id=submission_id)
    return response_data, status.SEE_OTHER, {'Location': redirect}
Esempio n. 3
0
def _check_status(params: MultiDict, session: Session,  submission_id: int,
                  token: str, **kwargs) -> None:
    """
    Check for cases in which the preview already exists.

    This will catch cases in which the submission is PDF-only, or otherwise
    requires no further compilation.
    """
    submitter, client = user_and_client_from_session(session)
    submission, submission_events = load_submission(submission_id)

    if not submission.submitter_compiled_preview \
            and not _must_process(submission):

        form = CompilationForm(params)  # Providing CSRF protection.
        if not form.validate():
            raise BadRequest('Invalid request; please try again.')

        command = ConfirmCompiledPreview(creator=submitter, client=client)
        try:
            submission, _ = save(command, submission_id=submission_id)
        except SaveError as e:
            alerts.flash_failure(Markup(
                'There was a problem carrying out your request. Please'
                f' try again. {SUPPORT}'
            ))
            logger.error('Error while saving command %s: %s',
                         command.event_id, e)
            raise InternalServerError('Could not save changes') from e
Esempio n. 4
0
 def test_flash_message(self, mock_flash):
     """Just flash a simple message."""
     alerts.flash_failure('The message')
     (data, category), kwargs = mock_flash.call_args
     self.assertEqual(data['message'], 'The message')
     self.assertIsInstance(data['message'], str)
     self.assertTrue(data['dismissable'])
     self.assertEqual(category, alerts.FAILURE)
Esempio n. 5
0
 def test_safe_flash_message(self, mock_flash):
     """Flash a simple message that is HTML-safe."""
     alerts.flash_failure('The message', safe=True)
     (data, category), kwargs = mock_flash.call_args
     self.assertEqual(data['message'], 'The message')
     self.assertIsInstance(data['message'], Markup)
     self.assertTrue(data['dismissable'])
     self.assertEqual(category, alerts.FAILURE)
Esempio n. 6
0
 def test_flash_message_no_dismiss(self, mock_flash):
     """Flash a simple message that can't be dismissed."""
     alerts.flash_failure('The message', dismissable=False)
     (data, category), kwargs = mock_flash.call_args
     self.assertEqual(data['message'], 'The message')
     self.assertIsInstance(data['message'], str)
     self.assertFalse(data['dismissable'])
     self.assertEqual(category, alerts.FAILURE)
Esempio n. 7
0
def _update(form: UploadForm,
            submission: Submission,
            stat: Upload,
            submitter: User,
            client: Optional[Client] = None,
            rdata: Dict[str, Any] = {}) -> Submission:
    """
    Update the :class:`.Submission` after an upload-related action.

    The submission is linked to the upload workspace via the
    :attr:`Submission.source_content` attribute. This is set using a
    :class:`SetUploadPackage` command. If the workspace identifier changes
    (e.g. on first upload), we want to execute :class:`SetUploadPackage` to
    make the association.

    Parameters
    ----------
    submission : :class:`Submission`
    _status : :class:`Upload`
    submitter : :class:`User`
    client : :class:`Client` or None

    """
    existing_upload = getattr(submission.source_content, 'identifier', None)

    commands = []
    if existing_upload == stat.identifier:
        command = UpdateUploadPackage(creator=submitter,
                                      client=client,
                                      checksum=stat.checksum,
                                      uncompressed_size=stat.size,
                                      compressed_size=stat.compressed_size,
                                      source_format=stat.source_format)
        commands.append(command)
        if submission.submitter_compiled_preview:
            commands.append(UnConfirmCompiledPreview(creator=submitter))
    else:
        command = SetUploadPackage(creator=submitter,
                                   client=client,
                                   identifier=stat.identifier,
                                   checksum=stat.checksum,
                                   compressed_size=stat.compressed_size,
                                   uncompressed_size=stat.size,
                                   source_format=stat.source_format)
        commands.append(command)

    if not validate_command(form, command, submission):
        logger.debug('Command validation failed')
        raise BadRequest(rdata)

    try:
        submission, _ = save(*commands, submission_id=submission.submission_id)
    except SaveError:
        alerts.flash_failure(
            Markup('There was a problem carrying out your request. Please try'
                   f' again. {PLEASE_CONTACT_SUPPORT}'))
    rdata['submission'] = submission
    return submission
Esempio n. 8
0
def cancel_request(method: str, params: MultiDict, session: Session,
                   submission_id: int, request_id: str, **kwargs) -> Response:
    submission, submission_events = load_submission(submission_id)

    # if request_type == WithdrawalRequest.NAME.lower():
    #     request_klass = WithdrawalRequest
    # elif request_type == CrossListClassificationRequest.NAME.lower():
    #     request_klass = CrossListClassificationRequest
    if request_id in submission.user_requests:
        user_request = submission.user_requests[request_id]
    else:
        raise NotFound('No such request')

    # # Get the most recent user request of this type.
    # this_request: Optional[UserRequest] = None
    # for user_request in submission.active_user_requests[::-1]:
    #     if isinstance(user_request, request_klass):
    #         this_request = user_request
    #         break
    # if this_request is None:
    #     raise NotFound('No such request')

    if not user_request.is_pending():
        raise BadRequest(f'Request is already {user_request.status}')

    response_data = {
        'submission': submission,
        'submission_id': submission.submission_id,
        'request_id': user_request.request_id,
        'user_request': user_request,
    }

    if method == 'GET':
        form = CancelRequestForm()
        response_data.update({'form': form})
        return response_data, status.OK, {}
    elif method == 'POST':
        form = CancelRequestForm(params)
        response_data.update({'form': form})
        if form.validate() and form.confirmed.data:
            user, client = user_and_client_from_session(session)
            command = CancelRequest(request_id=request_id,
                                    creator=user,
                                    client=client)
            if not validate_command(form, command, submission, 'confirmed'):
                raise BadRequest(response_data)

            try:
                save(command, submission_id=submission_id)
            except Exception as e:
                alerts.flash_failure("Whoops!" + str(e))
                raise InternalServerError(response_data) from e
            redirect = url_for('ui.create_submission')
            return {}, status.SEE_OTHER, {'Location': redirect}
        response_data.update({'form': form})
        raise BadRequest(response_data)
Esempio n. 9
0
def delete(method: str, params: MultiDict, session: Session,
           submission_id: int, **kwargs) -> Response:
    """
    Delete a submission, replacement, or other request.

    We never really DELETE-delete anything. The workhorse is
    :class:`.Rollback`. For new submissions, this just makes the submission
    inactive (disappear from user views). For replacements, or other kinds of
    requests that happen after the first version is announced, the submission
    is simply reverted back to the state of the last announcement.

    """
    submission, submission_events = load_submission(submission_id)
    response_data = {
        'submission': submission,
        'submission_id': submission.submission_id,
    }

    if method == 'GET':
        form = DeleteForm()
        response_data.update({'form': form})
        return response_data, status.OK, {}
    elif method == 'POST':
        form = DeleteForm(params)
        response_data.update({'form': form})
        if form.validate() and form.confirmed.data:
            user, client = user_and_client_from_session(session)
            command = Rollback(creator=user, client=client)
            if not validate_command(form, command, submission, 'confirmed'):
                raise BadRequest(response_data)

            try:
                save(command, submission_id=submission_id)
            except Exception as e:
                alerts.flash_failure("Whoops!")
                raise InternalServerError(response_data) from e
            redirect = url_for('ui.create_submission')
            return {}, status.SEE_OTHER, {'Location': redirect}
        response_data.update({'form': form})
        raise BadRequest(response_data)
Esempio n. 10
0
def compile_status(params: MultiDict, session: Session, submission_id: int,
                   token: str, **kwargs) -> Response:
    """
    Returns the status of a compilation.

    Parameters
    ----------
    session : :class:`Session`
        The authenticated session for the request.
    submission_id : int
        The identifier of the submission for which the upload is being made.
    token : str
        The original (encrypted) auth token on the request. Used to perform
        subrequests to the file management service.

    Returns
    -------
    dict
        Response data, to render in template.
    int
        HTTP status code. This should be ``200`` or ``303``, unless something
        goes wrong.
    dict
        Extra headers to add/update on the response. This should include
        the `Location` header for use in the 303 redirect response, if
        applicable.

    """
    submitter, client = user_and_client_from_session(session)
    submission, submission_events = load_submission(submission_id)
    form = CompilationForm()
    response_data = {
        'submission_id': submission_id,
        'submission': submission,
        'form': form,
        'status': None,
        'must_process': _must_process(submission)
    }

    # Not all submissions require processing.
    if not _must_process(submission):
        logger.debug('No processing required')
        return response_data, status.OK, {}

    # Determine whether the current state of the uploaded source content has
    # been compiled.
    source_id = submission.source_content.identifier
    source_state = submission.source_content.checksum
    try:
        compilation = Compiler.get_status(source_id, source_state, token)
    except exceptions.NotFound:     # Nothing to do.
        logger.debug('No such compilation')
        return response_data, status.OK, {}

    response_data['status'] = compilation.status
    response_data['current_compilation'] = compilation

    if compilation.status is Compilation.Status.SUCCEEDED:
        command = ConfirmCompiledPreview(creator=submitter, client=client)
        try:
            submission, _ = save(command, submission_id=submission_id)
        except SaveError:
            alerts.flash_failure(Markup(
                'There was a problem carrying out your request. Please try'
                f' again. {SUPPORT}'
            ))

    # if Compilation failure, then show errors, opportunity to restart.
    # if Compilation success, then show preview.
    terminal_states = [Compilation.Status.FAILED, Compilation.Status.SUCCEEDED]
    if compilation.status in terminal_states:
        response_data.update(_get_log(submission.source_content.identifier,
                                      submission.source_content.checksum,
                                      token))
    return response_data, status.OK, {}
Esempio n. 11
0
def request_cross(method: str, params: MultiDict, session: Session,
                  submission_id: int, **kwargs) -> Response:
    """Request cross-list classification for an announced e-print."""
    submitter, client = user_and_client_from_session(session)
    logger.debug(f'method: {method}, submission: {submission_id}. {params}')

    # Will raise NotFound if there is no such submission.
    submission, submission_events = load_submission(submission_id)

    # The submission must be announced for this to be a cross-list request.
    if not submission.is_announced:
        alerts.flash_failure(
            Markup("Submission must first be announced. See <a"
                   " href='https://arxiv.org/help/cross'>the arXiv help"
                   " pages</a> for details."))
        status_url = url_for('ui.create_submission')
        return {}, status.SEE_OTHER, {'Location': status_url}

    if method == 'GET':
        params = MultiDict({})

    params.setdefault("confirmed", False)
    params.setdefault("operation", CrossListForm.ADD)
    form = CrossListForm(params)
    selected = [v for v in form.selected.data if v]
    form.filter_choices(submission, session, exclude=selected)

    response_data = {
        'submission_id': submission_id,
        'submission': submission,
        'form': form,
        'selected': selected,
        'formset': CrossListForm.formset(selected)
    }
    if submission.primary_classification:
        response_data['primary'] = \
            CATEGORIES[submission.primary_classification.category]

    if method == 'POST':
        if not form.validate():
            raise BadRequest(response_data)

        if form.confirmed.data:     # Stop adding new categories, and submit.
            response_data['form'].operation.data = CrossListForm.ADD
            response_data['require_confirmation'] = True

            command = RequestCrossList(creator=submitter, client=client,
                                       categories=form.selected.data)
            if not validate_command(form, command, submission, 'category'):
                alerts.flash_failure(Markup(
                    "There was a problem with your request. Please try again."
                    f" {CONTACT_SUPPORT}"
                ))
                raise BadRequest(response_data)

            try:    # Submit the cross-list request.
                save(command, submission_id=submission_id)
            except SaveError as e:
                # This would be due to a database error, or something else
                # that likely isn't the user's fault.
                logger.error('Could not save cross list request event')
                alerts.flash_failure(Markup(
                    "There was a problem processing your request. Please try"
                    f" again. {CONTACT_SUPPORT}"
                ))
                raise InternalServerError(response_data) from e

            # Success! Send user back to the submission page.
            alerts.flash_success("Cross-list request submitted.")
            status_url = url_for('ui.create_submission')
            return {}, status.SEE_OTHER, {'Location': status_url}
        else:   # User is adding or removing a category.
            if form.operation.data:
                if form.operation.data == CrossListForm.REMOVE:
                    selected.remove(form.category.data)
                elif form.operation.data == CrossListForm.ADD:
                    selected.append(form.category.data)
                # Update the "remove" formset to reflect the change.
                response_data['formset'] = CrossListForm.formset(selected)
                response_data['selected'] = selected
            # Now that we've handled the request, get a fresh form for adding
            # more categories or submitting the request.
            response_data['form'] = CrossListForm()
            response_data['form'].filter_choices(submission, session,
                                                 exclude=selected)
            response_data['form'].operation.data = CrossListForm.ADD
            response_data['require_confirmation'] = True
            return response_data, status.OK, {}
    return response_data, status.OK, {}
Esempio n. 12
0
def jref(method: str, params: MultiDict, session: Session, submission_id: int,
         **kwargs) -> Response:
    """Set journal reference metadata on a announced submission."""
    creator, client = user_and_client_from_session(session)
    logger.debug(f'method: {method}, submission: {submission_id}. {params}')

    # Will raise NotFound if there is no such submission.
    submission, submission_events = load_submission(submission_id)

    # The submission must be announced for this to be a real JREF submission.
    if not submission.is_announced:
        alerts.flash_failure(
            Markup("Submission must first be announced. See "
                   "<a href='https://arxiv.org/help/jref'>"
                   "the arXiv help pages</a> for details."))
        status_url = url_for('ui.create_submission')
        return {}, status.SEE_OTHER, {'Location': status_url}

    # The form should be prepopulated based on the current state of the
    # submission.
    if method == 'GET':
        params = MultiDict({
            'doi': submission.metadata.doi,
            'journal_ref': submission.metadata.journal_ref,
            'report_num': submission.metadata.report_num
        })

    params.setdefault("confirmed", False)
    form = JREFForm(params)
    response_data = {
        'submission_id': submission_id,
        'submission': submission,
        'form': form,
    }

    if method == 'POST':
        # We require the user to confirm that they wish to proceed. We show
        # them a preview of what their paper's abs page will look like after
        # the proposed change. They can either make further changes, or
        # confirm and submit.
        if not form.validate():
            logger.debug('Invalid form data; return bad request')
            raise BadRequest(response_data)

        if not form.confirmed.data:
            response_data['require_confirmation'] = True
            logger.debug('Not confirmed')
            return response_data, status.OK, {}

        commands, valid = _generate_commands(form, submission, creator, client)

        if commands:  # Metadata has changed; we have things to do.
            if not all(valid):
                raise BadRequest(response_data)

            response_data['require_confirmation'] = True
            logger.debug('Form is valid, with data: %s', str(form.data))
            try:
                # Save the events created during form validation.
                submission, _ = save(*commands, submission_id=submission_id)
            except SaveError as e:
                logger.error('Could not save metadata event')
                raise InternalServerError(response_data) from e
            response_data['submission'] = submission

            # Success! Send user back to the submission page.
            alerts.flash_success("Journal reference updated")
            status_url = url_for('ui.create_submission')
            return {}, status.SEE_OTHER, {'Location': status_url}
    logger.debug('Nothing to do, return 200')
    return response_data, status.OK, {}
Esempio n. 13
0
def _new_file(params: MultiDict, pointer: FileStorage, session: Session,
              submission: Submission, rdata: Dict[str, Any], token: str) \
        -> Response:
    """
    Handle a POST request with a new file to add to an existing upload package.

    This occurs in the case that there is already an upload workspace
    associated with the submission. See the :attr:`Submission.source_content`
    attribute, which is set using :class:`SetUploadPackage`.

    Parameters
    ----------
    params : :class:`MultiDict`
        The form data from the request.
    pointer : :class:`FileStorage`
        The file upload stream.
    session : :class:`Session`
        The authenticated session for the request.
    submission : :class:`Submission`
        The submission for which the upload is being made.

    Returns
    -------
    dict
        Response data, to render in template.
    int
        HTTP status code. This should be ``303``, unless something goes wrong.
    dict
        Extra headers to add/update on the response. This should include
        the `Location` header for use in the 303 redirect response.

    """
    submitter, client = user_and_client_from_session(session)
    fm = FileManager.current_session()
    upload_id = submission.source_content.identifier

    # Using a form object provides some extra assurance that this is a legit
    # request; provides CSRF goodies.
    params['file'] = pointer
    form = UploadForm(params)
    rdata['form'] = form

    if not form.validate():
        logger.error('Invalid upload form: %s', form.errors)

        alerts.flash_failure("Something went wrong. Please try again.",
                             title="Whoops")
        # redirect = url_for('ui.file_upload',
        #                    submission_id=submission.submission_id)
        # return {}, status.SEE_OTHER, {'Location': redirect}
        logger.debug('Invalid form data')
        raise BadRequest(rdata)
    ancillary: bool = form.ancillary.data

    try:
        stat = fm.add_file(upload_id, pointer, token, ancillary=ancillary)
    except exceptions.RequestFailed as e:
        try:
            e_data = e.response.json()
        except Exception:
            e_data = None
        if e_data is not None and 'reason' in e_data:
            alerts.flash_failure(
                Markup('There was a problem carrying out your request:'
                       f' {e_data["reason"]}. {PLEASE_CONTACT_SUPPORT}'))
            raise BadRequest(rdata)
        alerts.flash_failure(
            Markup('There was a problem carrying out your request. Please try'
                   f' again. {PLEASE_CONTACT_SUPPORT}'))
        logger.debug('Failed to add file: %s', )
        logger.error(traceback.format_exc())
        raise InternalServerError(rdata) from e

    submission = _update(form, submission, stat, submitter, client, rdata)
    converted_size = tidy_filesize(stat.size)
    if stat.status is Upload.Status.READY:
        alerts.flash_success(
            f'Uploaded {pointer.filename} successfully. Total submission'
            f' package size is {converted_size}',
            title='Upload successful')
    elif stat.status is Upload.Status.READY_WITH_WARNINGS:
        alerts.flash_warning(
            f'Uploaded {pointer.filename} successfully. Total submission'
            f' package size is {converted_size}. See below for warnings.',
            title='Upload complete, with warnings')
    elif stat.status is Upload.Status.ERRORS:
        alerts.flash_warning(
            f'Uploaded {pointer.filename} successfully. Total submission'
            f' package size is {converted_size}. See below for errors.',
            title='Upload complete, with errors')
    status_data = stat.to_dict()
    alerts.flash_hidden(status_data, '_status')
    loc = url_for('ui.file_upload', submission_id=submission.submission_id)
    return {}, status.SEE_OTHER, {'Location': loc}
Esempio n. 14
0
def delete(method: str,
           params: MultiDict,
           session: Session,
           submission_id: int,
           token: Optional[str] = None,
           **kwargs) -> Response:
    """
    Handle a request to delete a file.

    The file will only be deleted if a POST request is made that also contains
    the ``confirmed`` parameter.

    The process can be initiated with a GET request that contains the
    ``path`` (key) for the file to be deleted. For example, a button on
    the upload interface may link to the deletion route with the file path
    as a query parameter. This will generate a deletion confirmation form,
    which can be POSTed to complete the action.

    Parameters
    ----------
    method : str
        ``GET`` or ``POST``
    params : :class:`MultiDict`
        The query or form data from the request.
    session : :class:`Session`
        The authenticated session for the request.
    submission_id : int
        The identifier of the submission for which the deletion is being made.
    token : str
        The original (encrypted) auth token on the request. Used to perform
        subrequests to the file management service.

    Returns
    -------
    dict
        Response data, to render in template.
    int
        HTTP status code. This should be ``200`` or ``303``, unless something
        goes wrong.
    dict
        Extra headers to add/update on the response. This should include
        the `Location` header for use in the 303 redirect response, if
        applicable.

    """
    if token is None:
        logger.debug('Missing auth token')
        raise BadRequest('Missing auth token')

    submission, submission_events = load_submission(submission_id)
    upload_id = submission.source_content.identifier
    submitter, client = user_and_client_from_session(session)

    rdata = {'submission': submission, 'submission_id': submission_id}

    if method == 'GET':
        # The only thing that we want to get from the request params on a GET
        # request is the file path. This way there is no way for a GET request
        # to trigger actual deletion. The user must explicitly indicate via
        # a valid POST that the file should in fact be deleted.
        params = MultiDict({'file_path': params['path']})

    form = DeleteFileForm(params)
    rdata.update({'form': form})

    if method == 'POST':
        if not (form.validate() and form.confirmed.data):
            logger.debug('Invalid form data')
            raise BadRequest(rdata)

        stat: Optional[Upload] = None
        try:
            file_path = form.file_path.data
            stat = FileManager.delete_file(upload_id, file_path, token)
            alerts.flash_success(
                f'File <code>{form.file_path.data}</code> was deleted'
                ' successfully',
                title='Deleted file successfully',
                safe=True)
        except exceptions.RequestForbidden:
            alerts.flash_failure(
                Markup(
                    'There was a problem authorizing your request. Please try'
                    f' again. {PLEASE_CONTACT_SUPPORT}'))
        except exceptions.BadRequest:
            alerts.flash_warning(
                Markup('Something odd happened when processing your request.'
                       f'{PLEASE_CONTACT_SUPPORT}'))
        except exceptions.RequestFailed:
            alerts.flash_failure(
                Markup(
                    'There was a problem carrying out your request. Please try'
                    f' again. {PLEASE_CONTACT_SUPPORT}'))

        if stat is not None:
            command = UpdateUploadPackage(creator=submitter,
                                          checksum=stat.checksum,
                                          uncompressed_size=stat.size,
                                          source_format=stat.source_format)
            if not validate_command(form, command, submission):
                logger.debug('Command validation failed')
                raise BadRequest(rdata)
            commands = [command]
            if submission.submitter_compiled_preview:
                commands.append(UnConfirmCompiledPreview(creator=submitter))
            try:
                submission, _ = save(*commands, submission_id=submission_id)
            except SaveError:
                alerts.flash_failure(
                    Markup(
                        'There was a problem carrying out your request. Please try'
                        f' again. {PLEASE_CONTACT_SUPPORT}'))
        redirect = url_for('ui.file_upload', submission_id=submission_id)
        return {}, status.SEE_OTHER, {'Location': redirect}
    return rdata, status.OK, {}
Esempio n. 15
0
def delete_all(method: str,
               params: MultiDict,
               session: Session,
               submission_id: int,
               token: Optional[str] = None,
               **kwargs) -> Response:
    """
    Handle a request to delete all files in the workspace.

    Parameters
    ----------
    method : str
        ``GET`` or ``POST``
    params : :class:`MultiDict`
        The query or form data from the request.
    session : :class:`Session`
        The authenticated session for the request.
    submission_id : int
        The identifier of the submission for which the deletion is being made.
    token : str
        The original (encrypted) auth token on the request. Used to perform
        subrequests to the file management service.

    Returns
    -------
    dict
        Response data, to render in template.
    int
        HTTP status code. This should be ``200`` or ``303``, unless something
        goes wrong.
    dict
        Extra headers to add/update on the response. This should include
        the `Location` header for use in the 303 redirect response, if
        applicable.

    """
    if token is None:
        logger.debug('Missing auth token')
        raise BadRequest('Missing auth token')

    submission, submission_events = load_submission(submission_id)
    upload_id = submission.source_content.identifier
    submitter, client = user_and_client_from_session(session)

    rdata = {'submission': submission, 'submission_id': submission_id}

    if method == 'GET':
        form = DeleteAllFilesForm()
        rdata.update({'form': form})
        return rdata, status.OK, {}
    elif method == 'POST':
        form = DeleteAllFilesForm(params)
        rdata.update({'form': form})

        if not (form.validate() and form.confirmed.data):
            logger.debug('Invalid form data')
            raise BadRequest(rdata)

        try:
            stat = FileManager.delete_all(upload_id, token)
        except exceptions.RequestForbidden as e:
            alerts.flash_failure(
                Markup(
                    'There was a problem authorizing your request. Please try'
                    f' again. {PLEASE_CONTACT_SUPPORT}'))
            logger.error('Encountered RequestForbidden: %s', e)
        except exceptions.BadRequest as e:
            alerts.flash_warning(
                Markup('Something odd happened when processing your request.'
                       f'{PLEASE_CONTACT_SUPPORT}'))
            logger.error('Encountered BadRequest: %s', e)
        except exceptions.RequestFailed as e:
            alerts.flash_failure(
                Markup(
                    'There was a problem carrying out your request. Please try'
                    f' again. {PLEASE_CONTACT_SUPPORT}'))
            logger.error('Encountered RequestFailed: %s', e)

        command = UpdateUploadPackage(creator=submitter,
                                      client=client,
                                      checksum=stat.checksum,
                                      uncompressed_size=stat.size,
                                      source_format=stat.source_format)
        commands = [command]
        if submission.submitter_compiled_preview:
            commands.append(UnConfirmCompiledPreview(creator=submitter))
        if not validate_command(form, command, submission):
            logger.debug('Command validation failed')
            raise BadRequest(rdata)

        try:
            submission, _ = save(*commands, submission_id=submission_id)
        except SaveError:
            alerts.flash_failure(
                Markup(
                    'There was a problem carrying out your request. Please try'
                    f' again. {PLEASE_CONTACT_SUPPORT}'))

        redirect = url_for('ui.file_upload', submission_id=submission_id)
        return {}, status.SEE_OTHER, {'Location': redirect}
    raise MethodNotAllowed('Method not supported')