Skip to content

Commit

Permalink
fix: support cron jobs (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
SKairinos committed May 13, 2024
1 parent 887670a commit 49f1863
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 14 deletions.
4 changes: 4 additions & 0 deletions codeforlife/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ def __init__(self, user_class: t.Type[AnyUser], *args, **kwargs):
super().__init__(*args, **kwargs)
self.user_class = user_class

@property
def query_params(self) -> t.Dict[str, str]: # type: ignore[override]
return super().query_params

@property
def user(self):
return t.cast(t.Union[AnyUser, AnonymousUser], super().user)
Expand Down
22 changes: 22 additions & 0 deletions codeforlife/tests/model_view_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ def update(
Args:
model: The model to update.
action: The name of the action.
data: The values for each field.
status_code_assertion: The expected status code.
make_assertions: A flag designating whether to make the default assertions.
Expand Down Expand Up @@ -443,6 +444,7 @@ def bulk_update(
Args:
models: The models to update.
data: The values for each field, for each model.
action: The name of the action.
status_code_assertion: The expected status code.
make_assertions: A flag designating whether to make the default assertions.
reverse_kwargs: The kwargs for the reverse URL.
Expand Down Expand Up @@ -577,6 +579,26 @@ def bulk_destroy(

return response

# --------------------------------------------------------------------------
# OTHER
# --------------------------------------------------------------------------

def cron_job(self, action: str):
"""Call a CRON job.
Args:
action: The name of the action.
Returns:
The HTTP response.
"""
response: Response = self.get(
self._test_case.reverse_action(action),
HTTP_X_APPENGINE_CRON="true",
)

return response


# pylint: enable=no-member

Expand Down
2 changes: 1 addition & 1 deletion codeforlife/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@

from .api import APIView
from .csrf import CookieView
from .decorators import action
from .decorators import action, cron_job
from .model import ModelViewSet
44 changes: 31 additions & 13 deletions codeforlife/views/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@
from rest_framework.decorators import action as _action


def _handler_name_to_url_path(handler: t.Callable):
url_path = handler.__name__
assert not re.match(
r"_{3,}", url_path
), "Cannot have 3+ underscores in action's name."

# Replace double underscores with sub-path. For example:
# name: "messages__replies" -> url-path: "messages/replies"
url_path = re.sub(r"_{2}", "/", url_path)

# Replace single underscore with dash. For example:
# name: "send_message" -> url-path: "send-message"
return re.sub(r"_", "-", url_path)


def action(**kwargs):
"""
Wraps DRF's @action decorator to support converting an action's name to a
Expand All @@ -32,21 +47,24 @@ def action(**kwargs):
def wrapper(handler: t.Callable):
# Set handler name as url-path if url-path is not specified.
if "url_path" not in kwargs:
url_path = handler.__name__
assert not re.match(
r"_{3,}", url_path
), "Cannot have 3+ underscores in action's name."
kwargs["url_path"] = _handler_name_to_url_path(handler)

# Replace double underscores with sub-path. For example:
# name: "messages__replies" -> url-path: "messages/replies"
url_path = re.sub(r"_{2}", "/", url_path)
return _action(**kwargs)(handler)

# Replace single underscore with dash. For example:
# name: "send_message" -> url-path: "send-message"
url_path = re.sub(r"_", "-", url_path)
return wrapper

kwargs["url_path"] = url_path

return _action(**kwargs)(handler)
def cron_job(handler: t.Callable):
# pylint: disable=line-too-long
"""
Create an action that is meant to be called by Google as a CRON job.
return wrapper
See https://github.com/ocadotechnology/codeforlife-workspace/blob/main/cron.yaml.
"""
# pylint: enable=line-too-long

return action(
detail=False,
methods=["get"],
url_path=f"cron/{_handler_name_to_url_path(handler)}",
)(handler)

0 comments on commit 49f1863

Please sign in to comment.