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 89d9f4a  Move code to add tokens to the storage interface
89d9f4a is described below

commit 89d9f4a9404b3571520a84f9510b2bc5d39574e9
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Aug 4 20:42:49 2025 +0100

    Move code to add tokens to the storage interface
---
 atr/routes/tokens.py            | 14 ++----
 atr/storage/__init__.py         |  5 +++
 atr/storage/writers/__init__.py |  3 +-
 atr/storage/writers/tokens.py   | 99 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 110 insertions(+), 11 deletions(-)

diff --git a/atr/routes/tokens.py b/atr/routes/tokens.py
index 9140928..89b38e7 100644
--- a/atr/routes/tokens.py
+++ b/atr/routes/tokens.py
@@ -52,6 +52,7 @@ import atr.jwtoken as jwtoken
 import atr.log as log
 import atr.models.sql as sql
 import atr.routes as routes
+import atr.storage as storage
 import atr.template as templates
 import atr.util as util
 
@@ -220,16 +221,9 @@ async def _create_token(uid: str, label: str | None) -> 
str:
     created = datetime.datetime.now(datetime.UTC)
     expires = created + datetime.timedelta(days=_EXPIRY_DAYS)
 
-    async with db.session() as data:
-        async with data.begin():
-            pat = sql.PersonalAccessToken(
-                asfuid=uid,
-                token_hash=token_hash,
-                created=created,
-                expires=expires,
-                label=label,
-            )
-            data.add(pat)
+    async with storage.write() as write:
+        wafc = write.as_foundation_committer()
+        await wafc.tokens.add_token(uid, token_hash, created, expires, label)
     return plaintext
 
 
diff --git a/atr/storage/__init__.py b/atr/storage/__init__.py
index 525c996..7735ec2 100644
--- a/atr/storage/__init__.py
+++ b/atr/storage/__init__.py
@@ -109,6 +109,7 @@ class WriteAsGeneralPublic(AccessCredentialsWrite):
     def __init__(self, write: Write, data: db.Session):
         self.checks = writers.checks.GeneralPublic(self, write, data)
         self.keys = writers.keys.GeneralPublic(self, write, data)
+        self.tokens = writers.tokens.GeneralPublic(self, write, data)
 
 
 class WriteAsFoundationCommitter(WriteAsGeneralPublic):
@@ -116,6 +117,7 @@ class WriteAsFoundationCommitter(WriteAsGeneralPublic):
         # TODO: We need a definitive list of ASF UIDs
         self.checks = writers.checks.FoundationCommitter(self, write, data)
         self.keys = writers.keys.FoundationCommitter(self, write, data)
+        self.tokens = writers.tokens.FoundationCommitter(self, write, data)
 
 
 class WriteAsCommitteeParticipant(WriteAsFoundationCommitter):
@@ -123,6 +125,7 @@ class 
WriteAsCommitteeParticipant(WriteAsFoundationCommitter):
         self.__committee_name = committee_name
         self.checks = writers.checks.CommitteeParticipant(self, write, data, 
committee_name)
         self.keys = writers.keys.CommitteeParticipant(self, write, data, 
committee_name)
+        self.tokens = writers.tokens.CommitteeParticipant(self, write, data, 
committee_name)
 
     @property
     def committee_name(self) -> str:
@@ -134,6 +137,7 @@ class WriteAsCommitteeMember(WriteAsCommitteeParticipant):
         self.__committee_name = committee_name
         self.checks = writers.checks.CommitteeMember(self, write, data, 
committee_name)
         self.keys = writers.keys.CommitteeMember(self, write, data, 
committee_name)
+        self.tokens = writers.tokens.CommitteeMember(self, write, data, 
committee_name)
 
     @property
     def committee_name(self) -> str:
@@ -146,6 +150,7 @@ class WriteAsFoundationAdmin(WriteAsCommitteeMember):
         self.__committee_name = committee_name
         # self.checks = writers.checks.FoundationAdmin(self, write, data, 
committee_name)
         self.keys = writers.keys.FoundationAdmin(self, write, data, 
committee_name)
+        # self.tokens = writers.tokens.FoundationAdmin(self, write, data, 
committee_name)
 
     @property
     def committee_name(self) -> str:
diff --git a/atr/storage/writers/__init__.py b/atr/storage/writers/__init__.py
index a7eb7dd..ddb82d7 100644
--- a/atr/storage/writers/__init__.py
+++ b/atr/storage/writers/__init__.py
@@ -17,5 +17,6 @@
 
 import atr.storage.writers.checks as checks
 import atr.storage.writers.keys as keys
+import atr.storage.writers.tokens as tokens
 
-__all__ = ["checks", "keys"]
+__all__ = ["checks", "keys", "tokens"]
diff --git a/atr/storage/writers/tokens.py b/atr/storage/writers/tokens.py
new file mode 100644
index 0000000..72e49d4
--- /dev/null
+++ b/atr/storage/writers/tokens.py
@@ -0,0 +1,99 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Removing this will cause circular imports
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import atr.db as db
+import atr.models.sql as sql
+import atr.storage as storage
+
+if TYPE_CHECKING:
+    import datetime
+
+
+class GeneralPublic:
+    def __init__(
+        self,
+        credentials: storage.WriteAsGeneralPublic,
+        write: storage.Write,
+        data: db.Session,
+    ):
+        self.__credentials = credentials
+        self.__write = write
+        self.__data = data
+        self.__asf_uid = write.authorisation.asf_uid
+
+
+class FoundationCommitter(GeneralPublic):
+    def __init__(self, credentials: storage.WriteAsFoundationCommitter, write: 
storage.Write, data: db.Session):
+        super().__init__(credentials, write, data)
+        self.__credentials = credentials
+        self.__write = write
+        self.__data = data
+        self.__asf_uid = write.authorisation.asf_uid
+
+    async def add_token(
+        self, uid: str, token_hash: str, created: datetime.datetime, expires: 
datetime.datetime, label: str | None
+    ) -> sql.PersonalAccessToken:
+        pat = sql.PersonalAccessToken(
+            asfuid=uid,
+            token_hash=token_hash,
+            created=created,
+            expires=expires,
+            label=label,
+        )
+        self.__data.add(pat)
+        await self.__data.commit()
+        return pat
+
+
+class CommitteeParticipant(FoundationCommitter):
+    def __init__(
+        self,
+        credentials: storage.WriteAsCommitteeParticipant,
+        write: storage.Write,
+        data: db.Session,
+        committee_name: str,
+    ):
+        super().__init__(credentials, write, data)
+        self.__credentials = credentials
+        self.__write = write
+        self.__data = data
+        self.__asf_uid = write.authorisation.asf_uid
+        self.__committee_name = committee_name
+
+
+class CommitteeMember(CommitteeParticipant):
+    def __init__(
+        self,
+        credentials: storage.WriteAsCommitteeMember,
+        write: storage.Write,
+        data: db.Session,
+        committee_name: str,
+    ):
+        super().__init__(credentials, write, data, committee_name)
+        self.__credentials = credentials
+        self.__write = write
+        self.__data = data
+        asf_uid = write.authorisation.asf_uid
+        if asf_uid is None:
+            raise storage.AccessError("No ASF UID")
+        self.__asf_uid = asf_uid
+        self.__committee_name = committee_name


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

Reply via email to