Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,22 @@ arXiv paper submission system
## Install & use

```bash
# Start the compiler api:
gcloud run services proxy tex2pdf-api-default --project arxiv-development --region us-central1 --port=9001

# Install gcld3 dependencies needed by arxiv-base metadata checks
# On linux:
# On linux, Install gcld3 dependencies needed by arxiv-base metadata checks
sudo apt-get install cmake libprotobuf-dev protobuf-compiler
uv sync
# On mac, you need a version of protobuf <= 21:
brew search protobuf

# On mac, you need a version of protobuf <= 21
brew install protobuf@21

pyenv shell 3.11 # or similar
source .venv/bin/activate
uv sync

# this will give you an Authorization token, save that and use a browser extension
# like modheader to add Authorization=eyJhb...
# Generate an Authorization token:
uv run python submit_ce/make_test_db.py bootstrap_db

# Use a browser extension like modheader to send the token for localhost
# add Authorization=eyJhb...

uv run python local_dev.py
open http://localhost:8000
```
Expand All @@ -39,4 +36,4 @@ open http://localhost:8000
gcloud auth configure-docker gcr.io # only needed once
docker build . -t gcr.io/arxiv-development/submit-ce/submit-ce-ui
docker push gcr.io/arxiv-development/submit-ce/submit-ce-ui
```
```
1 change: 0 additions & 1 deletion submit_ce/domain/uploads.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ class Workspace(BaseModel):
lifecycle: UploadLifecycleStates
locked: bool
identifier: str
source_format: SourceFormat = SourceFormat.UNKNOWN
checksum: Optional[str] = None
size: Optional[int] = None
"""Size in bytes of the uncompressed upload workspace."""
Expand Down
16 changes: 16 additions & 0 deletions submit_ce/ui/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,22 @@ class _FakePdf:
return submission


@pytest.fixture(scope="function")
def sub_files_tex(app, authorized_user, sub_files):
"""sub_files with source_format set to TEX, so review_files runs its
normal preflight/review flow rather than redirecting on the source_format
guard."""
with app.app_context():
user = authorized_user
ua = InternalClient(name=f"test_client_{__file__}")
submission, _ = current_app.api.save(
SetSourceFormat(creator=user, client=ua,
source_format=SourceFormat.TEX.value),
submission_id=sub_files.submission_id,
)
return submission


@pytest.fixture(scope="function")
def sub_reviewfiles(app, authorized_user, sub_files):
"""A submission that has passed through the review-files stage."""
Expand Down
13 changes: 10 additions & 3 deletions submit_ce/ui/controllers/new/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from submit_ce.domain.event.process import StartCompileSource
from submit_ce.domain.exceptions import SaveError
from submit_ce.domain.uploads import SourceFormat
from submit_ce.api.file_store import SubmissionFileStore
from submit_ce.ui import SUPPORT

Expand All @@ -21,7 +22,9 @@
from wtforms import SelectField

from ..util import validate_command
from submit_ce.ui.routes.flow_control import ready_for_next, stay_on_this_stage
from submit_ce.ui.routes.flow_control import (
ready_for_next, stay_on_this_stage, advance_to_current,
)
from submit_ce.ui.backend import get_submission


Expand Down Expand Up @@ -60,6 +63,10 @@ def file_process(method: str, params: MultiDict, session: Session,
applicable.

"""
submission, _ = get_submission(submission_id)
if submission.source_format == SourceFormat.PDF:
return advance_to_current(({}, status.OK, {}))

if method == "GET":
return compile_status(params, session, submission_id, token)
elif method == "POST":
Expand Down Expand Up @@ -211,7 +218,7 @@ def start_compilation(params: MultiDict, session: Session, submission_id: str,
# if 'reason' in result.extra and "produced from TeX source" in result.extra['reason']:
# alerts.flash_failure(TEX_PRODUCED_MARKUP)
# elif 'reason' in result.extra and 'docker' in result.extra['reason']:
# alerts.flash_failure(DOCKER_ERROR_MARKUOP)
# alerts.flash_failure(DOCKER_ERROR_MARKUP)
# else:
# alerts.flash_failure(f"Processing failed")
# else:
Expand Down Expand Up @@ -262,7 +269,7 @@ class CompilationForm(csrf.CSRFForm):
"submission is TeX produced is incorrect, you should send " \
"e-mail with your submission ID to " \
'<a href="mailto:help@arxiv.org">arXiv administrators.</a></p>')
DOCKER_ERROR_MARKUOP = \
DOCKER_ERROR_MARKUP = \
Markup("Our automatic TeX processing system has failed to launch. " \
"There is a good chance we are aware of the issue, but if the " \
"problem persists you should send e-mail with your submission " \
Expand Down
22 changes: 20 additions & 2 deletions submit_ce/ui/controllers/new/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from http import HTTPStatus as status
from typing import Tuple, Dict, Any, Optional, List

import httpx
from flask import current_app
from arxiv.auth.domain import Session
from arxiv.base import alerts
Expand All @@ -24,10 +25,13 @@
from wtforms import SelectField
from wtforms.validators import DataRequired

from submit_ce.domain.uploads import Workspace
from submit_ce.domain.uploads import Workspace, SourceFormat
from submit_ce.domain.exceptions import InvalidEvent, SaveError
from submit_ce.ui.controllers.util import validate_command
from submit_ce.ui.routes.flow_control import stay_on_this_stage, ready_for_next, return_to_parent_stage
from submit_ce.ui.routes.flow_control import (
stay_on_this_stage, ready_for_next, return_to_parent_stage,
return_to_previous_stage, advance_to_current,
)
from submit_ce.ui.backend import get_submission
from submit_ce.ui import SUPPORT

Expand Down Expand Up @@ -153,6 +157,12 @@ def review_files(method: str, params: MultiDict, session: Session,
if not workspace:
return return_to_parent_stage((rdata, status.OK, {}))

if submission.source_format == SourceFormat.PDF:
return advance_to_current((rdata, status.OK, {}))

if submission.source_format != SourceFormat.TEX:
return return_to_previous_stage((rdata, status.OK, {}))

if method == 'GET':
preflight_data, user_decisions_data = _load_or_create_preflight(
submission_id, params, session, token, workspace, submitter, client
Expand Down Expand Up @@ -418,3 +428,11 @@ def start_directives(params: MultiDict, session: Session, submission_id: str,
except SaveError as e:
alerts.flash_failure(f"We couldn't start directives. {SUPPORT}", title="Directives failed")
raise InternalServerError(response_data) from e
except httpx.HTTPError as e:
logger.error('Compile service error during StartDirectives for %s: %s',
submission_id, e)
alerts.flash_failure(
f"We couldn't start directives because the compile service"
f" is unavailable. {SUPPORT}",
title="Directives failed")
raise InternalServerError(response_data) from e
18 changes: 9 additions & 9 deletions submit_ce/ui/controllers/new/tests/test_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
from submit_ce.ui.controllers.new import review


def test_review_files_get_warning_via_http(app, authorized_client, sub_files,
def test_review_files_get_warning_via_http(app, authorized_client, sub_files_tex,
mocker):
"""End-to-end: GET /<id>/review_files triggers flash_warning when
_load_or_create_preflight yields no preflight data."""
mocker.patch.object(review, '_load_or_create_preflight',
return_value=(None, None))
mock_flash = mocker.patch.object(review.alerts, 'flash_warning')

url = f"/{sub_files.submission_id}/review_files"
url = f"/{sub_files_tex.submission_id}/review_files"
resp = authorized_client.get(url)

assert resp.status_code == status.OK
Expand Down Expand Up @@ -65,10 +65,10 @@ def _get_csrf(authorized_client, url, mocker):


def test_review_files_post_with_changes_redirects_to_parent(
app, authorized_client, sub_files, mocker):
app, authorized_client, sub_files_tex, mocker):
"""End-to-end POST: when _update_preflight reports changes, the controller
marks STAGE_PARENT and the flow redirects (303 SEE_OTHER)."""
url = f"/{sub_files.submission_id}/review_files"
url = f"/{sub_files_tex.submission_id}/review_files"
csrf = _get_csrf(authorized_client, url, mocker)

mock_update = mocker.patch.object(review, '_update_preflight',
Expand All @@ -83,10 +83,10 @@ def test_review_files_post_with_changes_redirects_to_parent(


def test_review_files_post_no_changes_no_preflight_flashes(
app, authorized_client, sub_files, mocker):
app, authorized_client, sub_files_tex, mocker):
"""End-to-end POST: when there are no changes but preflight is still
unavailable, the controller flashes a warning and stays on the stage."""
url = f"/{sub_files.submission_id}/review_files"
url = f"/{sub_files_tex.submission_id}/review_files"
csrf = _get_csrf(authorized_client, url, mocker)

mocker.patch.object(review, '_update_preflight', return_value=False)
Expand All @@ -105,10 +105,10 @@ def test_review_files_post_no_changes_no_preflight_flashes(


def test_review_files_post_no_changes_stores_zzrm_and_advances(
app, authorized_client, sub_files, mocker):
app, authorized_client, sub_files_tex, mocker):
"""End-to-end POST: when there are no changes and preflight is present,
the controller stores the merged zzrm and advances to the next stage."""
url = f"/{sub_files.submission_id}/review_files"
url = f"/{sub_files_tex.submission_id}/review_files"
csrf = _get_csrf(authorized_client, url, mocker)

mocker.patch.object(review, '_update_preflight', return_value=False)
Expand All @@ -131,7 +131,7 @@ def test_review_files_post_no_changes_stores_zzrm_and_advances(
fake_zzrm.from_dict.assert_called_once_with({'sources': []})
fake_zzrm.update_from_preflight.assert_called_once()
mock_store.store_zzrm.assert_called_once_with(
str(sub_files.submission_id), {'merged': True}
str(sub_files_tex.submission_id), {'merged': True}
)


Expand Down
11 changes: 7 additions & 4 deletions submit_ce/ui/controllers/new/tests/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def test_upload(app, authorized_client, sub_cross):
b"<title>Upload" in resp.data \
and b"<form " in resp.data


class TestUpload(CtrlBase):
"""Tests for :func:`submit_ce.controllers.upload`."""

Expand Down Expand Up @@ -160,8 +161,8 @@ def test_post_upload(self):
data, code, _ = upload.upload_files('POST', params, self.session,
submission_id, files=files,
token='footoken')
self.assertEqual(mock_api.save.call_count, 1,
'Saves the upload command via the api')
self.assertEqual(mock_api.save.call_count, 2,
'Saves UploadFiles and SetSourceFormat via the api')
self.assertEqual(code, status.OK)
self.assertEqual(get_controllers_desire(data), STAGE_RESHOW,
'Successful upload and reshow form')
Expand Down Expand Up @@ -229,8 +230,10 @@ def test_post_delete_confirmed(self):
self.session,
submission_id,
'footoken')
self.assertEqual(mock_api.save.call_count, 1,
'Saves the remove-files command via the api')
self.assertEqual(mock_api.save.call_count, 2,
'Saves RemoveFiles and SetSourceFormat via the api')
self.assertEqual(code, status.OK)
self.assertEqual(get_controllers_desire(data), STAGE_PARENT,
'Confirmed delete returns to the parent stage')


Loading
Loading