Skip to content

Commit

Permalink
django-unpoly-18 Cleanup and Django 4 Support
Browse files Browse the repository at this point in the history
- added Server side attributes
- added Django 4.X to poetry
- added is_unpoly to requests
- added layer to form attributes
- added success_url to forms
  • Loading branch information
Jannik Eilers committed Jan 2, 2023
1 parent 31b4afc commit 6366a05
Show file tree
Hide file tree
Showing 5 changed files with 356 additions and 701 deletions.
1 change: 1 addition & 0 deletions django_unpoly/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __call__(self, request):
up_params = self._get_up_params(request)
# Remove Up-Parameters sent by GET so they do not show up
request.GET = self._remove_up_params(request.GET, up_params)
request.is_unpoly = 'X-Up-Version' in request.headers

response: HttpResponseBase = self.get_response(request)

Expand Down
2 changes: 1 addition & 1 deletion django_unpoly/templates/up/form.up.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% extends "layout.html" %}

{% block card_body %}
<form id='up_form' method="post"{% if target %} up-target="{{ target }}" up-layer="root" up-fail-layer="any"{% endif %}{% if autosubmit %} up-autosubmit {% endif %}class="form-horizontal" autocomplete="off">
<form id='up_form' method="post"{% if target %} up-target="{{ target }}" up-layer="{{ layer }}" up-fail-layer="any"{% endif %}{% if autosubmit %} up-autosubmit {% endif %}class="form-horizontal" autocomplete="off">
{% csrf_token %}
{{ form }}
</form>
Expand Down
90 changes: 67 additions & 23 deletions django_unpoly/up.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,93 @@
from typing import Optional

from django.contrib.auth.mixins import LoginRequiredMixin
import typing
from django.http.response import HttpResponseBase
from django.utils.translation import gettext as _

from django_unpoly.exceptions import UpException


class UpModelIdMixin:
def up_id(self):
def up_id(self) -> str:
return f"{self.__class__.__name__}_{self.pk}"


class UpMixin:
def __init__(self):
self.up_target: Optional[str] = None # if the up_target is set, it will be sent as X-Up-Target Request-Header

# Unpoly Server protocol
up_target: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/X-Up-Target
up_clear_cache: typing.Union[str, None, typing.Callable] = '*' # https://unpoly.com/X-Up-Clear-Cache
up_accept_layer: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/X-Up-Accept-Layer
up_dismiss_layer: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/X-Up-Dismiss-Layer
up_events: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/X-Up-Events
up_fail_mode: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/X-Up-Fail-Mode
up_fail_target: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/X-Up-Fail-Target
up_location: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/https://unpoly.com/X-Up-Location
up_method: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/X-Up-Method
up_reload_from_time: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/X-Up-Reload-From-Time
up_title: typing.Union[str, None, typing.Callable] = None # https://unpoly.com/X-Up-Title

# Unpoly template
layer: typing.Union[str, typing.Callable] = 'root'
target: typing.Union[str, None, typing.Callable] = ':none' # :none = Do not replace anyting on site

def _get_value(self, attribute):
if callable(attribute):
return attribute()
else:
return attribute

def _get_context_list(self) -> set:
return {'target', 'layer', }

def get_context_data(self, *args, **kwargs):
for c in self._get_context_list():
_attr = getattr(self, c)
if _attr:
kwargs.update({c: self._get_value(_attr)})

return super().get_context_data(*args, **kwargs)

def _get_dispatch_list(self) -> dict:
return {
'up_target': 'X-Up-Target',
'up_clear_cache': 'X-Up-Clear-Cache',
'up_accept_layer': 'X-Up-Accept-Layer',
'up_dismiss_layer': 'X-Up-Dismiss-Layer',
'up_events': 'X-Up-Events',
'up_fail_mode': 'X-Up-Accept-Layer',
'up_fail_target': 'X-Up-Fail-Target',
'up_location': 'X-Up-Location',
'up_method': 'X-Up-Method',
'up_reload_from_time': 'X-Up-Reload-From-Time',
'up_title': 'X-Up-Title',
}

def dispatch(self, request, *args, **kwargs):
response = super().dispatch(request, *args, **kwargs)
if self.up_target:
response["X-Up-Target"] = str(self.up_target)
for _, up_key in self._get_dispatch_list().items():
_attr = getattr(self, _)
if _attr:
response[up_key] = self._get_value(_attr)
return response


class UpFormMixin(UpMixin):
autosubmit: bool = False

def form_invalid(self, *args, **kwargs):
# Signaling failed form submissions
# https://unpoly.com/up.protocol
response: HttpResponseBase = super().form_invalid(*args, **kwargs)
response.status_code = 422
return response

def _get_context_list(self):
return super()._get_context_list().union({'autosubmit', })

def get_success_url(self, *args, **kwargs):
if 'redirect' in self.request.GET:
return self.request.GET.get('redirect')
else:
return super().get_success_url(*args, **kwargs)

class UpDjangoConcurrencyMixin(UpMixin):
def get(self, request, *args, **kwargs):
Expand All @@ -49,18 +106,5 @@ def get(self, request, *args, **kwargs):
return result


class UpModelViewMixin(LoginRequiredMixin, UpFormMixin):
autosubmit: bool = False

def get_context_data(self, *args, **kwargs):
if "target" not in kwargs:
kwargs.update({"target": f"*[up-id='{self.object.up_id()}']"})
if "autosubmit" not in kwargs:
kwargs.update({"autosubmit": self.autosubmit})
return super().get_context_data(*args, **kwargs)

def get_success_url(self, *args, **kwargs):
try:
return self.request.GET.get("redirect")
except Exception:
return super().get_success_url(*args, **kwargs)
class UpModelViewMixin(UpFormMixin):
target: typing.Union[str, None, typing.Callable] = lambda self: f'*[up-id=\'{self.object.unpoly_id()}\']'
Loading

0 comments on commit 6366a05

Please sign in to comment.