From 0a01f893d67be7e188202a1d2505161a74eb3d93 Mon Sep 17 00:00:00 2001
From: Brian Maltzan
Date: Tue, 9 Jun 2026 09:12:14 -0400
Subject: [PATCH 1/5] update readme
---
README.md | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 1391a8e4..3ae910a6 100644
--- a/README.md
+++ b/README.md
@@ -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
```
@@ -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
-```
\ No newline at end of file
+```
From c4eb5bed6d33f52ad3eb63ee7126dbb9db18738b Mon Sep 17 00:00:00 2001
From: Brian Maltzan
Date: Tue, 9 Jun 2026 09:20:00 -0400
Subject: [PATCH 2/5] minor
---
submit_ce/ui/controllers/new/process.py | 4 ++--
submit_ce/ui/workflow/stages.py | 1 -
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/submit_ce/ui/controllers/new/process.py b/submit_ce/ui/controllers/new/process.py
index e1f71901..13252de6 100644
--- a/submit_ce/ui/controllers/new/process.py
+++ b/submit_ce/ui/controllers/new/process.py
@@ -211,7 +211,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:
@@ -262,7 +262,7 @@ class CompilationForm(csrf.CSRFForm):
"submission is TeX produced is incorrect, you should send " \
"e-mail with your submission ID to " \
'arXiv administrators.
')
-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 " \
diff --git a/submit_ce/ui/workflow/stages.py b/submit_ce/ui/workflow/stages.py
index bbd2cbdb..fc306728 100644
--- a/submit_ce/ui/workflow/stages.py
+++ b/submit_ce/ui/workflow/stages.py
@@ -102,7 +102,6 @@ class ReviewFiles(Stage):
"""The user is asked to review files for their submission with input
from preflight analysis.
"""
- #endpoint = 'review_files'
endpoint = 'review_files'
label = 'review your submission files'
title = "Review Files"
From c6ef9b667c3a97c8126781c6f8748602f436c126 Mon Sep 17 00:00:00 2001
From: Brian Maltzan
Date: Tue, 9 Jun 2026 11:53:31 -0400
Subject: [PATCH 3/5] Missing: block more_notifications
---
submit_ce/ui/templates/submit/file_upload.html | 2 ++
1 file changed, 2 insertions(+)
diff --git a/submit_ce/ui/templates/submit/file_upload.html b/submit_ce/ui/templates/submit/file_upload.html
index ee8bbdf0..fad71115 100644
--- a/submit_ce/ui/templates/submit/file_upload.html
+++ b/submit_ce/ui/templates/submit/file_upload.html
@@ -52,6 +52,7 @@
{% block title -%}Upload Files{%- endblock title %}
+{% block more_notifications %}
{% if immediate_notifications %}
{% for notification in immediate_notifications %}
@@ -62,6 +63,7 @@
{% endfor %}
{% endif %}
+{% endblock more_notifications %}
{% block important_text_box %}
From 0c76aa3b015fced7318ff2070b06c889ec4971a2 Mon Sep 17 00:00:00 2001
From: Brian Maltzan
Date: Wed, 10 Jun 2026 06:35:08 -0400
Subject: [PATCH 4/5] SUBMISSION-128: pdf only uploads
---
submit_ce/domain/uploads.py | 1 -
...est_pubusb_impl.py => test_pubsub_impl.py} | 0
submit_ce/ui/conftest.py | 16 ++++
submit_ce/ui/controllers/new/process.py | 9 +-
submit_ce/ui/controllers/new/review.py | 22 ++++-
.../ui/controllers/new/tests/test_review.py | 18 ++--
.../ui/controllers/new/tests/test_upload.py | 11 ++-
submit_ce/ui/controllers/new/upload.py | 88 +++++++++++++++----
submit_ce/ui/controllers/new/upload_delete.py | 21 ++++-
submit_ce/ui/routes/flow_control.py | 13 ++-
submit_ce/ui/routes/ui.py | 13 ++-
submit_ce/ui/workflow/conditions.py | 8 +-
12 files changed, 180 insertions(+), 40 deletions(-)
rename submit_ce/implementations/pubsub/tests/{test_pubusb_impl.py => test_pubsub_impl.py} (100%)
diff --git a/submit_ce/domain/uploads.py b/submit_ce/domain/uploads.py
index 80f9eacb..6c495f97 100644
--- a/submit_ce/domain/uploads.py
+++ b/submit_ce/domain/uploads.py
@@ -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."""
diff --git a/submit_ce/implementations/pubsub/tests/test_pubusb_impl.py b/submit_ce/implementations/pubsub/tests/test_pubsub_impl.py
similarity index 100%
rename from submit_ce/implementations/pubsub/tests/test_pubusb_impl.py
rename to submit_ce/implementations/pubsub/tests/test_pubsub_impl.py
diff --git a/submit_ce/ui/conftest.py b/submit_ce/ui/conftest.py
index d7a352c6..d8335dbe 100644
--- a/submit_ce/ui/conftest.py
+++ b/submit_ce/ui/conftest.py
@@ -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."""
diff --git a/submit_ce/ui/controllers/new/process.py b/submit_ce/ui/controllers/new/process.py
index 13252de6..c0311c97 100644
--- a/submit_ce/ui/controllers/new/process.py
+++ b/submit_ce/ui/controllers/new/process.py
@@ -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
@@ -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
@@ -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":
diff --git a/submit_ce/ui/controllers/new/review.py b/submit_ce/ui/controllers/new/review.py
index affe2b5d..a87d8109 100644
--- a/submit_ce/ui/controllers/new/review.py
+++ b/submit_ce/ui/controllers/new/review.py
@@ -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
@@ -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
@@ -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
@@ -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
diff --git a/submit_ce/ui/controllers/new/tests/test_review.py b/submit_ce/ui/controllers/new/tests/test_review.py
index ee0a3053..37bb903d 100644
--- a/submit_ce/ui/controllers/new/tests/test_review.py
+++ b/submit_ce/ui/controllers/new/tests/test_review.py
@@ -14,7 +14,7 @@
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 //review_files triggers flash_warning when
_load_or_create_preflight yields no preflight data."""
@@ -22,7 +22,7 @@ def test_review_files_get_warning_via_http(app, authorized_client, sub_files,
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
@@ -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',
@@ -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)
@@ -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)
@@ -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}
)
diff --git a/submit_ce/ui/controllers/new/tests/test_upload.py b/submit_ce/ui/controllers/new/tests/test_upload.py
index a891f30c..52b9b35a 100644
--- a/submit_ce/ui/controllers/new/tests/test_upload.py
+++ b/submit_ce/ui/controllers/new/tests/test_upload.py
@@ -32,6 +32,7 @@ def test_upload(app, authorized_client, sub_cross):
b"Upload" in resp.data \
and b"