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-releases.git


The following commit(s) were added to refs/heads/main by this push:
     new fcc034b  Make the form to generate an announcement preview more type 
safe
fcc034b is described below

commit fcc034b391e279071b4b75bb6590e62e44c6b782
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue Nov 11 16:51:33 2025 +0000

    Make the form to generate an announcement preview more type safe
---
 atr/post/preview.py | 79 +++++++++++++----------------------------------------
 1 file changed, 19 insertions(+), 60 deletions(-)

diff --git a/atr/post/preview.py b/atr/post/preview.py
index d036a23..f956806 100644
--- a/atr/post/preview.py
+++ b/atr/post/preview.py
@@ -15,46 +15,35 @@
 # specific language governing permissions and limitations
 # under the License.
 
-import quart
+import pydantic
 
 import atr.blueprints.post as post
 import atr.construct as construct
-import atr.forms as forms
+import atr.form as form
 import atr.log as log
-import atr.models.sql as sql
-import atr.storage as storage
 import atr.web as web
 
 
-class AnnouncePreviewForm(forms.Typed):
-    """Form for validating preview request data."""
-
-    subject = forms.optional("Subject")
-    body = forms.textarea("Body")
-
-
-class DeleteForm(forms.Typed):
-    """Form for deleting a release preview."""
-
-    release_name = forms.hidden()
-    project_name = forms.hidden()
-    version_name = forms.hidden()
-    confirm_delete = forms.string("Confirmation", 
validators=forms.constant("DELETE"))
-    submit = forms.submit("Delete preview")
+class AnnouncePreviewForm(form.Form):
+    body: str = form.label("Body", widget=form.Widget.TEXTAREA)
 
 
 @post.committer("/preview/announce/<project_name>/<version_name>")
-async def announce_preview(session: web.Committer, project_name: str, 
version_name: str) -> web.QuartResponse | str:
-    """Generate a preview of the announcement email body."""
+async def announce_preview(session: web.Committer, project_name: str, 
version_name: str) -> web.QuartResponse:
+    """Generate a preview of the announcement email body from JavaScript."""
 
-    # TODO: Where does this come from? A static template?
-    form = await AnnouncePreviewForm.create_form(data=await quart.request.form)
-    if not await form.validate_on_submit():
-        error_message = "Invalid preview request"
-        if form.errors:
-            error_details = "; ".join([f"{field}: {', '.join(errs)}" for 
field, errs in form.errors.items()])
-            error_message = f"{error_message}: {error_details}"
-        return web.TextResponse(f"Error: {error_message}", status=400)
+    form_data = await form.quart_request()
+
+    try:
+        # Because this is requested from JavaScript, we validate manually
+        # Otherwise errors redirect back to a page which does not exist
+        validated_form = form.validate(AnnouncePreviewForm, form_data)
+        if not isinstance(validated_form, AnnouncePreviewForm):
+            raise ValueError("Invalid form data")
+    except pydantic.ValidationError as e:
+        errors = e.errors()
+        error_details = "; ".join([f"{err['loc'][0]}: {err['msg']}" for err in 
errors])
+        return web.TextResponse(f"Error: Invalid preview request: 
{error_details}", status=400)
 
     try:
         # Construct options and generate body
@@ -64,40 +53,10 @@ async def announce_preview(session: web.Committer, 
project_name: str, version_na
             project_name=project_name,
             version_name=version_name,
         )
-        preview_body = await 
construct.announce_release_body(str(form.body.data), options)
+        preview_body = await 
construct.announce_release_body(validated_form.body, options)
 
         return web.TextResponse(preview_body)
 
     except Exception as e:
         log.exception("Error generating announcement preview:")
         return web.TextResponse(f"Error generating preview: {e!s}", status=500)
-
-
[email protected]("/preview/delete")
-async def delete(session: web.Committer) -> web.WerkzeugResponse:
-    """Delete a preview and all its associated files."""
-    import atr.get.root as root
-
-    # TODO: Where does this come from? A static template?
-    form = await DeleteForm.create_form(data=await quart.request.form)
-
-    if not await form.validate_on_submit():
-        for _field, errors in form.errors.items():
-            for error in errors:
-                await quart.flash(f"{error}", "error")
-        return await session.redirect(root.index)
-
-    release_name = form.release_name.data
-    project_name = form.project_name.data
-    version_name = form.version_name.data
-    if not (release_name and project_name and version_name):
-        return await session.redirect(root.index, error="Missing required 
parameters")
-
-    # Check that the user has access to the project
-    async with storage.write(session) as write:
-        wacp = await write.as_project_committee_participant(project_name)
-        await wacp.release.delete(
-            project_name, version_name, 
phase=sql.ReleasePhase.RELEASE_PREVIEW, include_downloads=False
-        )
-
-    return await session.redirect(root.index, success="Preview deleted 
successfully")


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

Reply via email to