From 58aec2b5f9627db0c5847855d8bfab02145ec84e Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 15 Apr 2026 16:54:33 -0400 Subject: [PATCH 01/12] Add SetProxyInformation to generate event for setting proxy information. [SUBMISSION-87] David --- submit_ce/domain/event/__init__.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/submit_ce/domain/event/__init__.py b/submit_ce/domain/event/__init__.py index 87ae1c7..ceee011 100644 --- a/submit_ce/domain/event/__init__.py +++ b/submit_ce/domain/event/__init__.py @@ -74,6 +74,7 @@ from ..submission import Submission, Author, \ Classification, License from ..exceptions import InvalidEvent +from submit_ce.domain.submission import ProxyInfo __all__ = [ make_event, @@ -219,6 +220,27 @@ def project(self, submission: Submission) -> Submission: return submission +class SetProxyInformation(Event): + """Set proxy information.""" + proxied_name: str + proxied_email: str + + def apply(self, submission: Submission) -> Submission: + # Temporary Debugging - works + logger.error( + "REPLAY apply SetProxyInformation: %s %s", + self.proxied_name, + self.proxied_email, + ) + + submission.proxy = ProxyInfo( + proxied_name=self.proxied_name, + proxied_email=self.proxied_email, + proxy_user=self.creator, + ) + return submission + + class ConfirmAuthorship(Event): """The submitting user asserts whether they are an author of the paper.""" From da7786b543d85d972a9842f7a0dac3ca8e7855d4 Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 15 Apr 2026 19:23:39 -0400 Subject: [PATCH 02/12] Add ProxyInfo dataclass. [SUBMISSION-87] David --- submit_ce/domain/submission.py | 45 +++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/submit_ce/domain/submission.py b/submit_ce/domain/submission.py index 717ce4a..213cff1 100644 --- a/submit_ce/domain/submission.py +++ b/submit_ce/domain/submission.py @@ -16,6 +16,28 @@ from .util import get_tzaware_utc_now +@dataclass +class ProxyInfo: + """ + Submission is made by submitter_id on behalf of someone else. + """ + proxied_name: str + proxied_email: str + proxy_user: User + + +def proxy_equal(a: ProxyInfo | None, b: ProxyInfo | None) -> bool: + if a is None and b is None: + return True + if a is None or b is None: + return False + return ( + a.proxied_name == b.proxied_name + and a.proxied_email == b.proxied_email + and a.proxy_user.identifier == b.proxy_user.identifier + ) + + @dataclass class Author: """Represents an author of a submission.""" @@ -303,7 +325,7 @@ class Submission: creator: User owner: User - proxy: Optional[User] = field(default=None) + proxy: Optional[ProxyInfo] = field(default=None) client: Optional[Client] = field(default=None) created: Optional[datetime] = field(default=None) updated: Optional[datetime] = field(default=None) @@ -364,6 +386,27 @@ class Submission: waivers: Dict[str, Waiver] = field(default_factory=dict) """Quality control waivers.""" + # ------------------------ + # Derived / presentation + # ------------------------ + @property + def contact_name(self) -> str: + """ + Who appears as the 'From' / contact name. + """ + if self.proxy: + return self.proxy.proxy_for_name + return self.submitter.full_name + + @property + def contact_email(self) -> str: + """ + Who appears as the 'From' / contact email. + """ + if self.proxy: + return self.proxy.proxy_for_email + return self.submitter.email + @property def features(self) -> Dict[str, Feature]: return {k: v for k, v in self.annotations.items() From 5de77d8aaab38fb2c0ef6d6a445565430814f9d6 Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 15 Apr 2026 19:26:41 -0400 Subject: [PATCH 03/12] Add ProxyInfo dataclass. [SUBMISSION-87] David --- .../legacy_implementation/interpolate.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/submit_ce/implementations/legacy_implementation/interpolate.py b/submit_ce/implementations/legacy_implementation/interpolate.py index 2d38c80..de757c7 100644 --- a/submit_ce/implementations/legacy_implementation/interpolate.py +++ b/submit_ce/implementations/legacy_implementation/interpolate.py @@ -33,6 +33,7 @@ SetDOI, SetJournalReference, SetMSCClassification, + SetProxyInformation, SetReportNumber, SetTitle, ) @@ -266,6 +267,13 @@ def _inject(self, event_type: Type[Event], **data: Any) -> None: def _apply(self, event: Event) -> None: self.submission = event.apply(self.submission) + + # Temporary + logger.error( + "AFTER _apply: submission.proxy=%r", + self.submission.proxy + ) + self.applied_events.append(event) def _backport_event(self, event: Event) -> None: @@ -322,4 +330,10 @@ def get_submission_state(self) -> Tuple[Submission, List[Event]]: assert self.submission is not None logger.debug('done; submission in state %s with %i events', self.submission.status, len(self.applied_events)) + # Temporary Debugging + logger.error( + "BEFORE RETURN: submission.proxy=%r", + self.submission.proxy + ) + return self.submission, self.applied_events From 033e1cd278f2e18d866f8a5781919fe1ce1e649e Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 15 Apr 2026 19:28:06 -0400 Subject: [PATCH 04/12] Store proxy information in legacy DB. [SUBMISSION-87] David --- .../legacy_implementation/models.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/submit_ce/implementations/legacy_implementation/models.py b/submit_ce/implementations/legacy_implementation/models.py index cb887b1..3eb0336 100644 --- a/submit_ce/implementations/legacy_implementation/models.py +++ b/submit_ce/implementations/legacy_implementation/models.py @@ -357,6 +357,24 @@ def update_from_submission(self, submission: domain.Submission) -> None: self.remote_addr = str(submission.client.remote_addr) self.remote_host = submission.client.remote_host or "" + # Legacy proxy compatibility + # + # ProxyInfo is Submit 2.0 state, persisted via events. + # The legacy DB proxy column is write‑only compatibility output. + if submission.proxy: + # historically this stored the proxy submitter's id + #self.proxy = submission.proxy.proxy_user.identifier # Nothing - see below + self.proxy = submission.creator.user_id # THIS IS CURRENTLY NOT WORKING + self.proxy = "Test" # Does not work - need to dig deeper + # NOTE: Need to figure out why creator id is empty. + # submission has creator (User) and owner (User) + # we also need to update submitter name and email to + # support backward compatibility with legacy + self.submitter_name = submission.proxy.proxied_name # works + self.submitter_email = submission.proxy.proxied_email # works + else: + self.proxy = None + @property def primary_classification(self) -> Optional['Category']: """Get the primary classification for this submission.""" From 1afc9c4625a19b716ae22c54ca1a5e117d7e7a4c Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 15 Apr 2026 20:20:13 -0400 Subject: [PATCH 05/12] Preserve proxy information (in progress). [SUBMISSION-87] David --- submit_ce/ui/controllers/new/verify_user.py | 50 ++++++++++++++++++--- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/submit_ce/ui/controllers/new/verify_user.py b/submit_ce/ui/controllers/new/verify_user.py index 54c077d..5bb49c5 100644 --- a/submit_ce/ui/controllers/new/verify_user.py +++ b/submit_ce/ui/controllers/new/verify_user.py @@ -18,16 +18,16 @@ from arxiv.auth.domain import Session from submit_ce.ui.auth import user_and_client_from_session -from submit_ce.domain.event import ConfirmContactInformation +from submit_ce.domain.event import ConfirmContactInformation, SetProxyInformation from submit_ce.ui.backend import get_submission from submit_ce.ui.controllers.util import validate_command from submit_ce.ui.routes.flow_control import ready_for_next, stay_on_this_stage +from submit_ce.domain.submission import ProxyInfo, proxy_equal +logger = logging.getLogger(__name__) # pylint: disable=C0103 -logger = logging.getLogger(__name__) # pylint: disable=C0103 - -Response = Tuple[Dict[str, Any], int, Dict[str, Any]] # pylint: disable=C0103 +Response = Tuple[Dict[str, Any], int, Dict[str, Any]] # pylint: disable=C0103 def verify(method: str, params: MultiDict, session: Session, @@ -43,17 +43,29 @@ def verify(method: str, params: MultiDict, session: Session, # Will raise NotFound if there is no such submission. submission, _ = get_submission(submission_id) may_proxy = scopes.PROXY_SUBMISSION in submitter.scopes + # may_proxy = True if method == 'GET' and submission.submitter_contact_verified: params['verify_user'] = 'true' + if method == "GET": + + logger.error( + "VERIFY_USER GET: submission.proxy=%r", + submission.proxy + ) + + if submission.proxy: + params['proxy_name'] = submission.proxy.proxied_name + params['proxy_email'] = submission.proxy.proxied_email + form = VerifyUserForm(params) response_data = { 'submission_id': submission_id, 'form': form, 'submission': submission, 'submitter': submitter, - 'user': session.user, # We want the most up-to-date representation. + 'user': session.user, # We want the most up-to-date representation. 'may_proxy': may_proxy, } @@ -76,10 +88,34 @@ def verify(method: str, params: MultiDict, session: Session, if not ok: return stay_on_this_stage((response_data, status.BAD_REQUEST, {})) - if submission.submitter_contact_verified: - return ready_for_next((response_data, status.OK,{})) + # We need to process proxy changes + # + # if submission.submitter_contact_verified: + # return ready_for_next((response_data, status.OK,{})) + + # NEW + existing_proxy = submission.proxy + + new_proxy = None + if may_proxy and (form.proxy_name.data or form.proxy_email.data): + new_proxy = ProxyInfo( + proxied_name=form.proxy_name.data.strip(), + proxied_email=form.proxy_email.data.strip(), + proxy_user=submitter, + ) + + if not proxy_equal(existing_proxy, new_proxy): + submission.proxy = new_proxy + cmd = SetProxyInformation( + creator=submitter, + client=client, + proxied_name=new_proxy.proxied_name, + proxied_email=new_proxy.proxied_email, + ) + submission, _ = current_app.api.save(cmd, submission_id=submission_id) cmd = ConfirmContactInformation(creator=submitter, client=client) + if validate_command(form, cmd, submission, 'verify_user'): submission, _ = current_app.api.save(cmd, submission_id=submission_id) response_data['submission'] = submission From 800a92f93b7ef29a7c2c63c7052f11cc3f16e47e Mon Sep 17 00:00:00 2001 From: "Brian D. Caruso" Date: Thu, 16 Apr 2026 13:02:38 -0400 Subject: [PATCH 06/12] Clarifies the docstr of interpolate.py --- .../legacy_implementation/interpolate.py | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/submit_ce/implementations/legacy_implementation/interpolate.py b/submit_ce/implementations/legacy_implementation/interpolate.py index de757c7..6e24b63 100644 --- a/submit_ce/implementations/legacy_implementation/interpolate.py +++ b/submit_ce/implementations/legacy_implementation/interpolate.py @@ -1,17 +1,24 @@ -""" -Inject events from outside the scope of the NG submission system. - -A core concept of the :mod:`arxiv.submission.domain.event` model is that -the state of a submission can be obtained by playing forward all of the -commands/events applied to it. That works when all agents that operate -on submission state are generating commands. The problem that we face in -the short term is that some operations will be performed by legacy components -that don't generate command/event data. - -The objective of the :class:`ClassicEventInterpolator` is to reconcile -NG events/commands with aspects of the classic database that are outside its -current purview. The logic in this module will need to change as the scope -of the NG submission data architecture expands. +"""Given a legacy 1.5 submission, make a submit 2.0 `List[Event]` that would create +a submission in that state. + +A core concept of the :mod:`arxiv.submission.domain.event` model is that the +state of a submission can be obtained by playing forward all of the +commands/events applied to it. This is called "event sourcing". Right now, +2026-04, we are not using event sourcing and submit 2.0 just writes to the db. +The events are still valuable because they are a high fidelity history of +changes to the submission. + +Event sourcing works when all agents that operate on submission state are +generating commands. The problem faced in the short term is that some +operations will be performed by legacy components that don't generate +command/event data. + +The objective of the :class:`ClassicEventInterpolator` is to reconcile NG +events/commands with the classic database that are outside its event system. + +The logic in this module will need to change as the scope of the NG submission +data architecture expands. + """ import logging From 2f1854e47dd78df7e42f33d5b9005aeb3ddcc3e9 Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 22 Apr 2026 13:07:27 -0400 Subject: [PATCH 07/12] Simplified SetProxyInformation event. Removed ClearProxyInformation event. [SUBMISSION-87] David --- submit_ce/domain/event/__init__.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/submit_ce/domain/event/__init__.py b/submit_ce/domain/event/__init__.py index ceee011..1060d2c 100644 --- a/submit_ce/domain/event/__init__.py +++ b/submit_ce/domain/event/__init__.py @@ -224,20 +224,17 @@ class SetProxyInformation(Event): """Set proxy information.""" proxied_name: str proxied_email: str + proxy_name: str def apply(self, submission: Submission) -> Submission: - # Temporary Debugging - works - logger.error( - "REPLAY apply SetProxyInformation: %s %s", - self.proxied_name, - self.proxied_email, - ) - - submission.proxy = ProxyInfo( - proxied_name=self.proxied_name, - proxied_email=self.proxied_email, - proxy_user=self.creator, - ) + # We need to use the Creator dataclass. This holds + # submitter_name and submitter_email (from legacy). + # Proxy name setting indicates that these fields are + # set by submitter and may not correspond to + # user_id (2.0) or submitter_id (1.5). + submission.creator.name = self.proxied_name + submission.creator.email = self.proxied_email + submission.proxy = self.proxy_name return submission From 1071b3e3fad06acd70fea97f3984be03f4f57cc5 Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 22 Apr 2026 13:18:13 -0400 Subject: [PATCH 08/12] Change proxy field to be string to match legacy DB. Removed ProxyInfo class. [SUBMISSION-87] David --- submit_ce/domain/submission.py | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/submit_ce/domain/submission.py b/submit_ce/domain/submission.py index 213cff1..784e0bc 100644 --- a/submit_ce/domain/submission.py +++ b/submit_ce/domain/submission.py @@ -16,16 +16,6 @@ from .util import get_tzaware_utc_now -@dataclass -class ProxyInfo: - """ - Submission is made by submitter_id on behalf of someone else. - """ - proxied_name: str - proxied_email: str - proxy_user: User - - def proxy_equal(a: ProxyInfo | None, b: ProxyInfo | None) -> bool: if a is None and b is None: return True @@ -325,7 +315,7 @@ class Submission: creator: User owner: User - proxy: Optional[ProxyInfo] = field(default=None) + proxy: Optional[str] = field(default=None) client: Optional[Client] = field(default=None) created: Optional[datetime] = field(default=None) updated: Optional[datetime] = field(default=None) @@ -386,26 +376,23 @@ class Submission: waivers: Dict[str, Waiver] = field(default_factory=dict) """Quality control waivers.""" - # ------------------------ # Derived / presentation - # ------------------------ + # These should eventually replace creator, since creator + # does not represent creator's submitter name and email when + # proxying a submissions for someone else. @property def contact_name(self) -> str: """ Who appears as the 'From' / contact name. """ - if self.proxy: - return self.proxy.proxy_for_name - return self.submitter.full_name + return self.creator.name @property def contact_email(self) -> str: """ Who appears as the 'From' / contact email. """ - if self.proxy: - return self.proxy.proxy_for_email - return self.submitter.email + return self.creator.email @property def features(self) -> Dict[str, Feature]: From 2fc06eb1e3af4cac2f09b58b473181312ea97cdd Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 22 Apr 2026 13:27:50 -0400 Subject: [PATCH 09/12] Removed ProxyInfo import. [SUBMISSION-87] David --- submit_ce/domain/event/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submit_ce/domain/event/__init__.py b/submit_ce/domain/event/__init__.py index 1060d2c..81dd0ca 100644 --- a/submit_ce/domain/event/__init__.py +++ b/submit_ce/domain/event/__init__.py @@ -74,7 +74,7 @@ from ..submission import Submission, Author, \ Classification, License from ..exceptions import InvalidEvent -from submit_ce.domain.submission import ProxyInfo + __all__ = [ make_event, From ea7f6cc3cb77398512d8e6cef273ffc6464b3b18 Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 22 Apr 2026 13:28:58 -0400 Subject: [PATCH 10/12] Removed proxy_equal function. [SUBMISSION-87] David --- submit_ce/domain/submission.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/submit_ce/domain/submission.py b/submit_ce/domain/submission.py index 784e0bc..ab77af6 100644 --- a/submit_ce/domain/submission.py +++ b/submit_ce/domain/submission.py @@ -15,19 +15,6 @@ from .process import ProcessStatus from .util import get_tzaware_utc_now - -def proxy_equal(a: ProxyInfo | None, b: ProxyInfo | None) -> bool: - if a is None and b is None: - return True - if a is None or b is None: - return False - return ( - a.proxied_name == b.proxied_name - and a.proxied_email == b.proxied_email - and a.proxy_user.identifier == b.proxy_user.identifier - ) - - @dataclass class Author: """Represents an author of a submission.""" From a8c13162038c9558ce82f0c740413b2d09315a3c Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 22 Apr 2026 13:37:40 -0400 Subject: [PATCH 11/12] Add proxy field copy from DB. [SUBMISSION-87] David --- .../legacy_implementation/db.py | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/submit_ce/implementations/legacy_implementation/db.py b/submit_ce/implementations/legacy_implementation/db.py index e6a4a8a..6da9757 100644 --- a/submit_ce/implementations/legacy_implementation/db.py +++ b/submit_ce/implementations/legacy_implementation/db.py @@ -55,11 +55,10 @@ from .models import DBEvent from .patch import patch_cross, patch_hold, patch_jref, patch_withdrawal from submit_ce import domain -from submit_ce.domain import Event, Submission, User, WithdrawalRequest, CrossListClassificationRequest, License +from submit_ce.domain import Event, Submission, User, WithdrawalRequest, CrossListClassificationRequest, License from submit_ce.domain.event import SetJournalReference, SetDOI, SetReportNumber, CreateSubmission, Rollback from submit_ce.domain.exceptions import NoSuchSubmission - logger = logging.getLogger(__name__) logger.propagate = False @@ -70,11 +69,14 @@ # retry = _retry retry: Callable[..., Callable[[F], F]] = _retry + + # wraps: Callable[[F], F] = _wraps def handle_operational_errors(func: F) -> F: """Catch SQLAlchemy OperationalErrors and raise :class:`.Unavailable`.""" + @wraps(func) def inner(*args: Any, **kwargs: Any) -> Any: try: @@ -90,6 +92,7 @@ def inner(*args: Any, **kwargs: Any) -> Any: raise OperationalError('Classic database unavailable', getattr(e, 'params', None), getattr(e, 'orig', e)) from e + # return inner return cast(F, inner) @@ -128,7 +131,7 @@ def get_events(session: SQLAlchemySession, submission_id: str) -> List[Event]: .filter(DBEvent.submission_id == submission_id) \ .order_by(DBEvent.created) events = [datum.to_event() for datum in event_data] - if not events: # No events, no dice. + if not events: # No events, no dice. logger.error('No events for submission %s', submission_id) raise NoSuchSubmission(f'Submission {submission_id} not found') return events @@ -193,9 +196,9 @@ def get_submission(session: SQLAlchemySession, submission_id: str, for_update: b .filter(models.Submission.submission_id != submission_id) \ .order_by(models.Submission.submission_id.asc()) - if for_update: # Lock these rows as well. + if for_update: # Lock these rows as well. subsequent_query = subsequent_query.with_for_update(read=True) - subsequent_rows = list(subsequent_query) # Execute query. + subsequent_rows = list(subsequent_query) # Execute query. logger.debug('Got subsequent_rows: %s', subsequent_rows) try: @@ -223,7 +226,6 @@ def get_submission(session: SQLAlchemySession, submission_id: str, for_update: b return interpolator.get_submission_state() - # @retry(ClassicBaseException, tries=3, delay=1) @handle_operational_errors def store_event(session: SQLAlchemySession, event: Event, before: Optional[Submission], after: Submission) -> Tuple[Event, Submission]: @@ -265,15 +267,15 @@ def store_event(session: SQLAlchemySession, event: Event, before: Optional[Submi doc_id: Optional[int] = None # This is the case that we have a new submission. - if before is None: # and isinstance(after, Submission): + if before is None: # and isinstance(after, Submission): dbs = models.Submission(type=models.Submission.NEW_SUBMISSION) dbs.update_from_submission(after) this_is_a_new_submission = True - else: # Otherwise we're making an update for an existing submission. + else: # Otherwise we're making an update for an existing submission. this_is_a_new_submission = False - if before.arxiv_id is not None: #: + if before.arxiv_id is not None: #: # After the original submission is announced, a new Document row is # created. This Document is shared by all subsequent Submission rows. doc_id = _load_document_id(session, before.arxiv_id, before.version) @@ -283,18 +285,18 @@ def store_event(session: SQLAlchemySession, event: Event, before: Optional[Submi # database. if after.version > before.version: dbs = _create_replacement(doc_id, before.arxiv_id, - after.version, after, event.created) + after.version, after, event.created) elif isinstance(event, Rollback) and before.version > 1: dbs = _delete_replacement(session, doc_id, before.arxiv_id, - before.version) + before.version) # Withdrawals also require a new row, and they use the most recent # version number. elif isinstance(event, RequestWithdrawal): dbs = _create_withdrawal(doc_id, event.reason, - before.arxiv_id, after.version, after, - event.created) + before.arxiv_id, after.version, after, + event.created) elif isinstance(event, RequestCrossList): dbs = _create_crosslist(doc_id, event.categories, before.arxiv_id, after.version, after, @@ -304,7 +306,7 @@ def store_event(session: SQLAlchemySession, event: Event, before: Optional[Submi # also requires a new row. The version number is not incremented. elif before.is_announced and type(event) in JREFEvents: dbs = _create_jref(session, doc_id, before.arxiv_id, after.version, after, - event.created) + event.created) elif isinstance(event, CancelRequest): dbs = _cancel_request(session, event, before, after) @@ -341,7 +343,7 @@ def store_event(session: SQLAlchemySession, event: Event, before: Optional[Submi session.add(db_event) event.committed = True - log.handle(session, event, before, after) # Create admin log entry. + log.handle(session, event, before, after) # Create admin log entry. # Update the domain event and submission states with the submission ID. # This should carry forward the original submission ID, even if the @@ -456,7 +458,7 @@ def _create_withdrawal(document_id: int, reason: str, paper_id: str, document_id=document_id, version=version, remote_addr=submission.client.remote_addr, - remote_host=submission.client.remote_host, + remote_host=submission.client.remote_host, ) dbs.update_withdrawal(submission, reason, paper_id, version, created) return dbs @@ -578,8 +580,8 @@ def to_submission(row: models.Submission, primary = row.primary_classification if row.submitter is None: submitter = domain.PublicUser(user_id=str(row.submitter_id), - email=row.submitter_email, - name=row.submitter_name) + email=row.submitter_email, + name=row.submitter_name) else: submitter = row.get_submitter() if submission_id is None: @@ -587,8 +589,13 @@ def to_submission(row: models.Submission, else: submission_id = str(submission_id) - client = HttpClient(remote_addr = row.remote_addr, - remote_host = row.remote_host) + if row.proxy: + proxy = str(row.proxy) + else: + proxy = None + + client = HttpClient(remote_addr=row.remote_addr, + remote_host=row.remote_host) license: Optional[domain.License] = None if row.license: @@ -646,7 +653,8 @@ def to_submission(row: models.Submission, primary_classification=primary_clsn, secondary_classification=secondary_clsn, arxiv_id=row.doc_paper_id, - version=row.version + version=row.version, + proxy=proxy ) if row.sticky_status == row.ON_HOLD or row.status == row.ON_HOLD: submission = patch_hold(submission, row) @@ -682,7 +690,7 @@ def load(rows: Iterable[models.Submission]) -> Optional[domain.Submission]: # Creation time isn't all that precise in the classic database, so # we'll use submission ID instead. these_version_rows = sorted([v for v in version_rows], - key=lambda o: o.submission_id) + key=lambda o: o.submission_id) logger.debug('Version %s: %s', version, version_rows) # We use the original ID to track the entire lifecycle of the # submission in NG. @@ -752,8 +760,8 @@ def announce_submission(session: SQLAlchemySession, submission_id: str) -> None: head.status = Submission.ANNOUNCED if head.document is None: paper_id = datetime.now().strftime('%s')[-4:] \ - + "." \ - + datetime.now().strftime('%s')[-5:] + + "." \ + + datetime.now().strftime('%s')[-5:] head.document = models.Document(paper_id=paper_id) head.doc_paper_id = paper_id session.add(head) @@ -763,11 +771,3 @@ def announce_submission(session: SQLAlchemySession, submission_id: str) -> None: def _get_head_idx(session: SQLAlchemySession, rows: List[Submission]) -> int: """bdc34: Not sure what this is""" raise NotImplementedError() - - - - - - - - From ce12fd0158031e1f79010fdceb68aa9dc1c92c83 Mon Sep 17 00:00:00 2001 From: David Fielding Date: Wed, 22 Apr 2026 13:44:46 -0400 Subject: [PATCH 12/12] Clean out unnecessary code after simplifying implementation. [SUBMISSION-87] David --- .../legacy_implementation/models.py | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/submit_ce/implementations/legacy_implementation/models.py b/submit_ce/implementations/legacy_implementation/models.py index 3eb0336..8e86cd8 100644 --- a/submit_ce/implementations/legacy_implementation/models.py +++ b/submit_ce/implementations/legacy_implementation/models.py @@ -357,23 +357,8 @@ def update_from_submission(self, submission: domain.Submission) -> None: self.remote_addr = str(submission.client.remote_addr) self.remote_host = submission.client.remote_host or "" - # Legacy proxy compatibility - # - # ProxyInfo is Submit 2.0 state, persisted via events. - # The legacy DB proxy column is write‑only compatibility output. - if submission.proxy: - # historically this stored the proxy submitter's id - #self.proxy = submission.proxy.proxy_user.identifier # Nothing - see below - self.proxy = submission.creator.user_id # THIS IS CURRENTLY NOT WORKING - self.proxy = "Test" # Does not work - need to dig deeper - # NOTE: Need to figure out why creator id is empty. - # submission has creator (User) and owner (User) - # we also need to update submitter name and email to - # support backward compatibility with legacy - self.submitter_name = submission.proxy.proxied_name # works - self.submitter_email = submission.proxy.proxied_email # works - else: - self.proxy = None + self.proxy = submission.proxy + @property def primary_classification(self) -> Optional['Category']: