This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git


The following commit(s) were added to refs/heads/main by this push:
     new 2b12d77  Move code to record a user vote to the vote writer
2b12d77 is described below

commit 2b12d779d30eec147ed552c85c36be24ff021f6b
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Sep 11 18:44:27 2025 +0100

    Move code to record a user vote to the vote writer
---
 atr/routes/vote.py          | 57 ++------------------------------------------
 atr/storage/__init__.py     |  9 +++++++
 atr/storage/writers/vote.py | 58 +++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 65 insertions(+), 59 deletions(-)

diff --git a/atr/routes/vote.py b/atr/routes/vote.py
index bed8378..cb1ce7d 100644
--- a/atr/routes/vote.py
+++ b/atr/routes/vote.py
@@ -18,7 +18,6 @@
 import quart
 import werkzeug.wrappers.response as response
 
-import atr.db as db
 import atr.db.interaction as interaction
 import atr.forms as forms
 import atr.log as log
@@ -27,7 +26,6 @@ import atr.models.sql as sql
 import atr.routes as routes
 import atr.routes.compose as compose
 import atr.storage as storage
-import atr.tasks.message as message
 import atr.util as util
 
 
@@ -147,7 +145,8 @@ async def selected_post(session: routes.CommitterSession, 
project_name: str, ver
     if await form.validate_on_submit():
         vote = str(form.vote_value.data)
         comment = str(form.vote_comment.data)
-        email_recipient, error_message = await _send_vote(session, release, 
vote, comment)
+        async with 
storage.write_as_committee_participant(release.committee.name) as wacm:
+            email_recipient, error_message = await 
wacm.vote.send_user_vote(release, vote, comment, session.fullname)
         if error_message:
             return await session.redirect(
                 selected, project_name=project_name, 
version_name=version_name, error=error_message
@@ -166,55 +165,3 @@ async def selected_post(session: routes.CommitterSession, 
project_name: str, ver
         return await session.redirect(
             selected, project_name=project_name, version_name=version_name, 
error=error_message
         )
-
-
-async def _send_vote(
-    session: routes.CommitterSession,
-    release: sql.Release,
-    vote: str,
-    comment: str,
-) -> tuple[str, str]:
-    # Get the email thread
-    latest_vote_task = await interaction.release_latest_vote_task(release)
-    if latest_vote_task is None:
-        return "", "No vote task found."
-    vote_thread_mid = interaction.task_mid_get(latest_vote_task)
-    if vote_thread_mid is None:
-        return "", "No vote thread found."
-
-    # Construct the reply email
-    original_subject = latest_vote_task.task_args["subject"]
-
-    # Arguments for the task to cast a vote
-    email_recipient = latest_vote_task.task_args["email_to"]
-    email_sender = f"{session.uid}@apache.org"
-    subject = f"Re: {original_subject}"
-    body = [f"{vote.lower()} ({session.uid}) {session.fullname}"]
-    if comment:
-        body.append(f"{comment}")
-        # Only include the signature if there is a comment
-        body.append(f"-- \n{session.fullname} ({session.uid})")
-    body_text = "\n\n".join(body)
-    in_reply_to = vote_thread_mid
-
-    # TODO: Move this to the storage interface
-    task = sql.Task(
-        status=sql.TaskStatus.QUEUED,
-        task_type=sql.TaskType.MESSAGE_SEND,
-        task_args=message.Send(
-            email_sender=email_sender,
-            email_recipient=email_recipient,
-            subject=subject,
-            body=body_text,
-            in_reply_to=in_reply_to,
-        ).model_dump(),
-        asf_uid=util.unwrap(session.uid),
-        project_name=release.project.name,
-        version_name=release.version,
-    )
-    async with db.session() as data:
-        data.add(task)
-        await data.flush()
-        await data.commit()
-
-    return email_recipient, ""
diff --git a/atr/storage/__init__.py b/atr/storage/__init__.py
index 4b195f9..86b1dc4 100644
--- a/atr/storage/__init__.py
+++ b/atr/storage/__init__.py
@@ -446,6 +446,15 @@ async def write_as_committee_member(
         yield w.as_committee_member(committee_name)
 
 
[email protected]
+async def write_as_committee_participant(
+    committee_name: str,
+    asf_uid: str | None | ArgumentNoneType = ArgumentNone,
+) -> AsyncGenerator[WriteAsCommitteeParticipant]:
+    async with write(asf_uid) as w:
+        yield w.as_committee_participant(committee_name)
+
+
 @contextlib.asynccontextmanager
 async def write_as_project_committee_member(
     project_name: str,
diff --git a/atr/storage/writers/vote.py b/atr/storage/writers/vote.py
index 416f343..424e876 100644
--- a/atr/storage/writers/vote.py
+++ b/atr/storage/writers/vote.py
@@ -29,7 +29,6 @@ import atr.revision as revision
 import atr.storage as storage
 import atr.tasks.message as message
 import atr.tasks.vote as tasks_vote
-import atr.user as user
 import atr.util as util
 
 
@@ -76,6 +75,57 @@ class CommitteeParticipant(FoundationCommitter):
         self.__asf_uid = asf_uid
         self.__committee_name = committee_name
 
+    async def send_user_vote(
+        self,
+        release: sql.Release,
+        vote: str,
+        comment: str,
+        fullname: str,
+    ) -> tuple[str, str]:
+        # Get the email thread
+        latest_vote_task = await interaction.release_latest_vote_task(release)
+        if latest_vote_task is None:
+            return "", "No vote task found."
+        vote_thread_mid = interaction.task_mid_get(latest_vote_task)
+        if vote_thread_mid is None:
+            return "", "No vote thread found."
+
+        # Construct the reply email
+        original_subject = latest_vote_task.task_args["subject"]
+
+        # Arguments for the task to cast a vote
+        email_recipient = latest_vote_task.task_args["email_to"]
+        email_sender = f"{self.__asf_uid}@apache.org"
+        subject = f"Re: {original_subject}"
+        body = [f"{vote.lower()} ({self.__asf_uid}) {fullname}"]
+        if comment:
+            body.append(f"{comment}")
+            # Only include the signature if there is a comment
+            body.append(f"-- \n{fullname} ({self.__asf_uid})")
+        body_text = "\n\n".join(body)
+        in_reply_to = vote_thread_mid
+
+        # TODO: Move this to the storage interface
+        task = sql.Task(
+            status=sql.TaskStatus.QUEUED,
+            task_type=sql.TaskType.MESSAGE_SEND,
+            task_args=message.Send(
+                email_sender=email_sender,
+                email_recipient=email_recipient,
+                subject=subject,
+                body=body_text,
+                in_reply_to=in_reply_to,
+            ).model_dump(),
+            asf_uid=self.__asf_uid,
+            project_name=release.project.name,
+            version_name=release.version,
+        )
+        self.__data.add(task)
+        await self.__data.flush()
+        await self.__data.commit()
+
+        return email_recipient, ""
+
 
 class CommitteeMember(CommitteeParticipant):
     def __init__(
@@ -377,6 +427,6 @@ class CommitteeMember(CommitteeParticipant):
         # (The message should be shown on the vote resolution page)
         return task
 
-    def __committee_member_or_admin(self, committee: sql.Committee, asf_uid: 
str) -> None:
-        if not (user.is_committee_member(committee, asf_uid) or 
user.is_admin(asf_uid)):
-            raise storage.AccessError("You do not have permission to perform 
this action")
+    # def __committee_member_or_admin(self, committee: sql.Committee, asf_uid: 
str) -> None:
+    #     if not (user.is_committee_member(committee, asf_uid) or 
user.is_admin(asf_uid)):
+    #         raise storage.AccessError("You do not have permission to perform 
this action")


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to