Skip to content

Commit

Permalink
Finish class based views (part 1)
Browse files Browse the repository at this point in the history
  • Loading branch information
barseghyanartur committed Jul 11, 2022
1 parent eaabee4 commit b5f7f3c
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 5 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,31 @@ are used for versioning (schema follows below):
# ...
]
- Class-based permissions (work only in combination with class-based views).

Example:

.. code-block:: python
from fobi.permissions.definitions import edit_form_entry_permissions
from fobi.permissions.generic import BasePermission
from fobi.permissions.helpers import (
any_permission_required_func, login_required,
)
class EditFormEntryPermission(BasePermission):
"""Permission to edit form entries."""
def has_permission(self, request, view) -> bool:
return login_required(request) and any_permission_required_func(
edit_form_entry_permissions
)(request.user)
def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and any_permission_required_func(
edit_form_entry_permissions
)(request.user) and obj.user == request.user
0.18
----
2022-06-23
Expand Down
59 changes: 58 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ Main features and highlights
- Developer-friendly API, which allows to edit existing or build new form
fields and handlers without touching the core.
- Support for custom user model.
- Class based views (and class-based permissions). Forms have an
owner (``auth.User``). Default permissions are set for the owner, but
class-based views provide a lot of freedom and can be easily customized.
- `Theming`_. There are 4 ready to use `Bundled themes`_: "Bootstrap 3",
"Foundation 5", "Simple" (with editing interface in style of Django admin)
and "DjangoCMS admin style" theme (which is another simple theme with editing
Expand Down Expand Up @@ -127,7 +130,6 @@ Roadmap
Some of the upcoming/in-development features/improvements are:

- Implement disabling forms based on dates.
- Class based views.
- Cloning of forms.
- JSON schema support.
- Webpack integration.
Expand Down Expand Up @@ -1179,6 +1181,61 @@ Add the callback module to ``INSTALLED_APPS``.
# ...
)
Class-based views
=================
Views
-----
Migration to class based views is simple. Only your project's ``urls.py``
would change:

.. code-block:: python
urlpatterns = [
# ...
url(r'^fobi/', include('fobi.urls.class_based.view')),
url(r'^fobi/', include('fobi.urls.class_based.edit')),
# ...
]
To use function based views, simply replace the previous line with:

.. code-block:: python
urlpatterns = [
# ...
url(r'^fobi/', include('fobi.urls.view')),
url(r'^fobi/', include('fobi.urls.edit')),
# ...
]
Permissions
-----------

Class-based permissions work only in combination with class-based views.

Example:

.. code-block:: python
from fobi.permissions.definitions import edit_form_entry_permissions
from fobi.permissions.generic import BasePermission
from fobi.permissions.helpers import (
any_permission_required_func, login_required,
)
class EditFormEntryPermission(BasePermission):
"""Permission to edit form entries."""
def has_permission(self, request, view) -> bool:
return login_required(request) and any_permission_required_func(
edit_form_entry_permissions
)(request.user)
def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and any_permission_required_func(
edit_form_entry_permissions
)(request.user) and obj.user == request.user
Suggestions
===========
Custom action for the form
Expand Down
25 changes: 25 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,31 @@ are used for versioning (schema follows below):
# ...
]
- Class-based permissions (work only in combination with class-based views).

Example:

.. code-block:: python
from fobi.permissions.definitions import edit_form_entry_permissions
from fobi.permissions.generic import BasePermission
from fobi.permissions.helpers import (
any_permission_required_func, login_required,
)
class EditFormEntryPermission(BasePermission):
"""Permission to edit form entries."""
def has_permission(self, request, view) -> bool:
return login_required(request) and any_permission_required_func(
edit_form_entry_permissions
)(request.user)
def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and any_permission_required_func(
edit_form_entry_permissions
)(request.user) and obj.user == request.user
0.18
----
2022-06-23
Expand Down
59 changes: 58 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ Main features and highlights
- Developer-friendly API, which allows to edit existing or build new form
fields and handlers without touching the core.
- Support for custom user model.
- Class based views (and class-based permissions). Forms have an
owner (``auth.User``). Default permissions are set for the owner, but
class-based views provide a lot of freedom and can be easily customized.
- `Theming`_. There are 4 ready to use `Bundled themes`_: "Bootstrap 3",
"Foundation 5", "Simple" (with editing interface in style of Django admin)
and "DjangoCMS admin style" theme (which is another simple theme with editing
Expand Down Expand Up @@ -127,7 +130,6 @@ Roadmap
Some of the upcoming/in-development features/improvements are:

- Implement disabling forms based on dates.
- Class based views.
- Cloning of forms.
- JSON schema support.
- Webpack integration.
Expand Down Expand Up @@ -1179,6 +1181,61 @@ Add the callback module to ``INSTALLED_APPS``.
# ...
)
Class-based views
=================
Views
-----
Migration to class based views is simple. Only your project's ``urls.py``
would change:

.. code-block:: python
urlpatterns = [
# ...
url(r'^fobi/', include('fobi.urls.class_based.view')),
url(r'^fobi/', include('fobi.urls.class_based.edit')),
# ...
]
To use function based views, simply replace the previous line with:

.. code-block:: python
urlpatterns = [
# ...
url(r'^fobi/', include('fobi.urls.view')),
url(r'^fobi/', include('fobi.urls.edit')),
# ...
]
Permissions
-----------

Class-based permissions work only in combination with class-based views.

Example:

.. code-block:: python
from fobi.permissions.definitions import edit_form_entry_permissions
from fobi.permissions.generic import BasePermission
from fobi.permissions.helpers import (
any_permission_required_func, login_required,
)
class EditFormEntryPermission(BasePermission):
"""Permission to edit form entries."""
def has_permission(self, request, view) -> bool:
return login_required(request) and any_permission_required_func(
edit_form_entry_permissions
)(request.user)
def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and any_permission_required_func(
edit_form_entry_permissions
)(request.user) and obj.user == request.user
Suggestions
===========
Custom action for the form
Expand Down
33 changes: 33 additions & 0 deletions src/fobi/permissions/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ def has_permission(self, request, view) -> bool:
edit_form_entry_permissions
)(request.user)

def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and any_permission_required_func(
edit_form_entry_permissions
)(request.user) and obj.user == request.user


class DeleteFormEntryPermission(BasePermission):
"""Permission to delete form entries."""
Expand All @@ -71,6 +76,11 @@ def has_permission(self, request, view) -> bool:
delete_form_entry_permissions
)(request.user)

def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and any_permission_required_func(
delete_form_entry_permissions
)(request.user) and obj.user == request.user


class AddFormElementEntryPermission(BasePermission):
"""Permission to add form element entries."""
Expand All @@ -89,6 +99,11 @@ def has_permission(self, request, view) -> bool:
edit_form_element_entry_permission
)(request.user)

def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and permissions_required_func(
edit_form_element_entry_permission
)(request.user) and obj.form_entry.user == request.user


class DeleteFormElementEntryPermission(BasePermission):
"""Permission to delete form element entries."""
Expand All @@ -98,6 +113,11 @@ def has_permission(self, request, view) -> bool:
delete_form_element_entry_permission
)(request.user)

def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and permissions_required_func(
delete_form_element_entry_permission
)(request.user) and obj.form_entry.user == request.user


class AddFormHandlerEntryPermission(BasePermission):
"""Permission to add form handler entries."""
Expand All @@ -107,6 +127,9 @@ def has_permission(self, request, view) -> bool:
add_form_handler_entry_permission
)(request.user)

def has_object_permission(self, request, view, obj) -> bool:
return self.has_permission(request, view)


class EditFormHandlerEntryPermission(BasePermission):
"""Permission to edit form handler entries."""
Expand All @@ -116,6 +139,11 @@ def has_permission(self, request, view) -> bool:
edit_form_handler_entry_permission
)(request.user)

def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and permissions_required_func(
edit_form_handler_entry_permission
)(request.user) and obj.form_entry.user == request.user


class DeleteFormHandlerEntryPermission(BasePermission):
"""Permission to delete form handler entries."""
Expand All @@ -125,6 +153,11 @@ def has_permission(self, request, view) -> bool:
delete_form_handler_entry_permission
)(request.user)

def has_object_permission(self, request, view, obj) -> bool:
return login_required(request) and permissions_required_func(
delete_form_handler_entry_permission
)(request.user) and obj.form_entry.user == request.user


class ViewFormEntryPermission(AllowAnyPermission):
"""Permission to view form entries."""
5 changes: 4 additions & 1 deletion src/fobi/permissions/generic.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""
Provides a set of pluggable permission policies.
Mostly snatched from Django REST Framework.
Inspired by Django REST Framework class-based permissions.
`BasePermissions` forbids everything by default.
"""

__title__ = "fobi.permissions.generic"
Expand Down
2 changes: 1 addition & 1 deletion src/fobi/tests/test_browser_build_dynamic_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ def test_2004_submit_form(self, wait=WAIT_FOR):
# find out why and fix. As temporary workaround, we're waiting
# twice as long as the normal timeout.
self.take_screenshot("submit_success_page")
WebDriverWait(self.driver, timeout=TIMEOUT*2).until(
WebDriverWait(self.driver, timeout=TIMEOUT).until(
lambda driver: driver.find_element_by_xpath(
"""//div[contains(text(), 'Form {0} was submitted """
"""successfully.') """
Expand Down
2 changes: 1 addition & 1 deletion src/fobi/views/class_based.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ def get_object(self, queryset=None):
pk=self.kwargs.get(self.pk_url_kwarg),
)
self.check_object_permissions(self.request, obj)
return obj

# Add support for browsers which only accept GET and POST for now.
def get(self, request, *args, **kwargs):
Expand All @@ -180,7 +181,6 @@ def delete(self, request, *args, **kwargs):
"""Delete."""
self.object = self.get_object()
self._run_before_plugin_entry_delete(request, self.object)

form_entry = self.object.form_entry
plugin = self.object.get_plugin(request=request)
plugin.request = request
Expand Down

0 comments on commit b5f7f3c

Please sign in to comment.