Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Batch action form errors with empty checkbox #262

Open
mrharpo opened this issue Aug 18, 2023 · 1 comment
Open

Bug: Batch action form errors with empty checkbox #262

mrharpo opened this issue Aug 18, 2023 · 1 comment
Labels
bug Something isn't working

Comments

@mrharpo
Copy link
Contributor

mrharpo commented Aug 18, 2023

Describe the bug
When I have a batch action form with a single <input type="checkbox", if the box is unchecked, the form does not parse properly during request.form().

multipart.exceptions.MultipartParseError: Did not find CR at end of boundary (40)

The same error happens with type="radio" when submitted with options unselected.

To Reproduce

class ArticleView(ModelView):
    actions = ['test', 'delete']

    @action(
        name='test',
        text='Test',
        confirmation='Are you sure?',
        form="""
        <form>
            <div class="mt-3">
                <input type="checkbox" id="check" name="check">
                <label for="check">Breaks unless you check it</label>
            </div>
        </form>
        """,
    )
    async def make_published_action(self, request: Request, pks: List[Any]) -> str:
        data: FormData = await request.form()
        print(data)

Environment (please complete the following information):

  • Starlette-Admin version: 0.11.1
  • ORM/ODMs: SQLAlchemy, SQLModel

Additional context

Did not find CR at end of boundary (40)
INFO:     127.0.0.1:63960 - "POST /api/user/action?pks=1&name=test HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/anyio/streams/memory.py", line 98, in receive
    return self.receive_nowait()
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/anyio/streams/memory.py", line 93, in receive_nowait
    raise WouldBlock
anyio.WouldBlock

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 174, in call_next
    message = await recv_stream.receive()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/anyio/streams/memory.py", line 118, in receive
    raise EndOfStream
anyio.EndOfStream

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 408, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/applications.py", line 116, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 55, in wrapped_app
    raise exc
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 44, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/routing.py", line 746, in __call__
    await route.handle(scope, receive, send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/routing.py", line 459, in handle
    await self.app(scope, receive, send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/applications.py", line 116, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 206, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/starlette_admin/contrib/sqla/middleware.py", line 28, in dispatch
    return await call_next(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 180, in call_next
    raise app_exc
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 166, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/sessions.py", line 80, in __call__
    await self.app(scope, receive, send_wrapper)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 206, in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/starlette_admin/auth.py", line 286, in dispatch
    return await call_next(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 180, in call_next
    raise app_exc
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 166, in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 55, in wrapped_app
    raise exc
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 44, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/routing.py", line 746, in __call__
    await route.handle(scope, receive, send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/routing.py", line 288, in handle
    await self.app(scope, receive, send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/routing.py", line 75, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 55, in wrapped_app
    raise exc
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 44, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/routing.py", line 70, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/starlette_admin/base.py", line 318, in handle_action
    handler_return = await model.handle_action(request, pks, name)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/starlette_admin/contrib/sqla/view.py", line 108, in handle_action
    return await super().handle_action(request, pks, name)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/starlette_admin/views.py", line 342, in handle_action
    handler_return = await handler(request, pks)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/examples/authlib/app.py", line 99, in make_published_action
    data: FormData = await request.form()
                     ^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/requests.py", line 267, in _get_form
    self._form = await multipart_parser.parse()
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/starlette/formparsers.py", line 255, in parse
    parser.write(chunk)
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/multipart/multipart.py", line 1058, in write
    l = self._internal_write(data, data_len)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harpo/gbh/clams/starlette-admin/.venv/lib/python3.11/site-packages/multipart/multipart.py", line 1136, in _internal_write
    raise e
multipart.exceptions.MultipartParseError: Did not find CR at end of boundary (40)
@mrharpo
Copy link
Contributor Author

mrharpo commented Oct 4, 2023

Adding this workaround here as well, in case anyone needs it:

Add a hidden input in the form with a value (including ""). Kludex/python-multipart#38 (comment)

        <form>
            <input type="checkbox" id="check" name="check">
            <label for="check">Doesn't break, thanks to hidden value!</label>
            <input type="hidden" name="_" value="">
        </form>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant