Skip to content

Commit

Permalink
add read_only option to change_password and register endpoints (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dantownsend committed Jun 22, 2022
1 parent 66d302e commit bdd2178
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 2 deletions.
20 changes: 19 additions & 1 deletion piccolo_api/change_password/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
from jinja2 import Environment, FileSystemLoader
from starlette.endpoints import HTTPEndpoint, Request
from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse, RedirectResponse
from starlette.responses import (
HTMLResponse,
PlainTextResponse,
RedirectResponse,
)
from starlette.status import HTTP_303_SEE_OTHER

from piccolo_api.session_auth.tables import SessionsBase
Expand Down Expand Up @@ -47,6 +51,10 @@ def _session_table(self) -> t.Optional[t.Type[SessionsBase]]:
def _session_cookie_name(self) -> t.Optional[str]:
raise NotImplementedError

@abstractproperty
def _read_only(self) -> bool:
raise NotImplementedError

def render_template(
self,
request: Request,
Expand Down Expand Up @@ -85,6 +93,11 @@ async def get(self, request: Request) -> Response:
return RedirectResponse(self._login_url)

async def post(self, request: Request) -> Response:
if self._read_only:
return PlainTextResponse(
content="Running in read only mode", status_code=405
)

# Some middleware (for example CSRF) has already awaited the request
# body, and adds it to the request.
body = request.scope.get("form")
Expand Down Expand Up @@ -188,6 +201,7 @@ def change_password(
session_cookie_name: t.Optional[str] = "id",
template_path: t.Optional[str] = None,
styles: t.Optional[Styles] = None,
read_only: bool = False,
) -> t.Type[ChangePasswordEndpoint]:
"""
An endpoint for changing passwords.
Expand All @@ -209,6 +223,9 @@ def change_password(
as a basis for your custom template.
:param styles:
Modify the appearance of the HTML template using CSS.
:read_only:
If ``True``, the endpoint only responds to GET requests. It's not
commonly needed, except when running demos.
"""
template_path = (
Expand All @@ -227,5 +244,6 @@ class _ChangePasswordEndpoint(ChangePasswordEndpoint):
_styles = styles or Styles()
_session_table = session_table
_session_cookie_name = session_cookie_name
_read_only = read_only

return _ChangePasswordEndpoint
20 changes: 19 additions & 1 deletion piccolo_api/register/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
from starlette.datastructures import URL
from starlette.endpoints import HTTPEndpoint, Request
from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse, RedirectResponse
from starlette.responses import (
HTMLResponse,
PlainTextResponse,
RedirectResponse,
)
from starlette.status import HTTP_303_SEE_OTHER

from piccolo_api.shared.auth.styles import Styles
Expand Down Expand Up @@ -59,6 +63,10 @@ def _captcha(self) -> t.Optional[Captcha]:
def _styles(self) -> Styles:
raise NotImplementedError

@abstractproperty
def _read_only(self) -> bool:
raise NotImplementedError

def render_template(
self, request: Request, template_context: t.Dict[str, t.Any] = {}
) -> HTMLResponse:
Expand All @@ -84,6 +92,11 @@ async def get(self, request: Request) -> HTMLResponse:
return self.render_template(request)

async def post(self, request: Request) -> Response:
if self._read_only:
return PlainTextResponse(
content="Running in read only mode.", status_code=405
)

# Some middleware (for example CSRF) has already awaited the request
# body, and adds it to the request.
body = request.scope.get("form")
Expand Down Expand Up @@ -197,6 +210,7 @@ def register(
user_defaults: t.Optional[t.Dict[str, t.Any]] = None,
captcha: t.Optional[Captcha] = None,
styles: t.Optional[Styles] = None,
read_only: bool = False,
) -> t.Type[RegisterEndpoint]:
"""
An endpoint for register user.
Expand Down Expand Up @@ -224,6 +238,9 @@ def register(
See :class:`Captcha <piccolo_api.shared.auth.captcha.Captcha>`.
:param styles:
Modify the appearance of the HTML template using CSS.
:read_only:
If ``True``, the endpoint only responds to GET requests. It's not
commonly needed, except when running demos.
"""
template_path = (
Expand All @@ -241,5 +258,6 @@ class _RegisterEndpoint(RegisterEndpoint):
_user_defaults = user_defaults
_captcha = captcha
_styles = styles or Styles()
_read_only = read_only

return _RegisterEndpoint
17 changes: 17 additions & 0 deletions tests/change_password/test_change_password.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Note - most tests for the `change_password` endpoint are in `test_session.py`

from unittest import TestCase

from starlette.routing import Route, Router
from starlette.testclient import TestClient

from piccolo_api.change_password.endpoints import change_password


class TestChangePassword(TestCase):
def test_change_password(self):
app = Router(routes=[Route("/", change_password(read_only=True))])
client = TestClient(app)
response = client.post("/")
self.assertTrue(response.status_code, 405)
self.assertTrue(response.content, "Running in read only mode.")
17 changes: 17 additions & 0 deletions tests/register/test_register.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Note - most tests for the `register` endpoint are in `test_session.py`

from unittest import TestCase

from starlette.routing import Route, Router
from starlette.testclient import TestClient

from piccolo_api.register.endpoints import register


class TestRegister(TestCase):
def test_read_only(self):
app = Router(routes=[Route("/", register(read_only=True))])
client = TestClient(app)
response = client.post("/")
self.assertTrue(response.status_code, 405)
self.assertTrue(response.content, "Running in read only mode.")

0 comments on commit bdd2178

Please sign in to comment.