mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-07 14:25:37 +00:00
Allow editors to subscribe to a form view
This commit is contained in:
parent
731c1c70d5
commit
a9527603e9
11 changed files with 151 additions and 11 deletions
backend/src/baserow/contrib/database
changelog/entries/unreleased/bug
enterprise/backend
src/baserow_enterprise/role
tests/baserow_enterprise_tests/role
premium/backend/src/baserow_premium
web-frontend/modules/database/components/view/form
|
@ -686,6 +686,7 @@ class DatabaseConfig(AppConfig):
|
|||
object_scope_type_registry.register(TokenObjectScopeType())
|
||||
|
||||
from baserow.contrib.database.views.operations import (
|
||||
CanReceiveNotificationOnSubmitFormViewOperationType,
|
||||
UpdateViewFieldOptionsOperationType,
|
||||
)
|
||||
|
||||
|
@ -826,6 +827,9 @@ class DatabaseConfig(AppConfig):
|
|||
operation_type_registry.register(CreateAndUsePersonalViewOperationType())
|
||||
operation_type_registry.register(ReadViewOperationType())
|
||||
operation_type_registry.register(UpdateViewOperationType())
|
||||
operation_type_registry.register(
|
||||
CanReceiveNotificationOnSubmitFormViewOperationType()
|
||||
)
|
||||
operation_type_registry.register(DeleteViewOperationType())
|
||||
operation_type_registry.register(DuplicateViewOperationType())
|
||||
operation_type_registry.register(CreateViewFilterOperationType())
|
||||
|
|
|
@ -75,7 +75,6 @@ from baserow.contrib.database.views.operations import (
|
|||
UpdateViewFilterGroupOperationType,
|
||||
UpdateViewFilterOperationType,
|
||||
UpdateViewGroupByOperationType,
|
||||
UpdateViewOperationType,
|
||||
UpdateViewPublicOperationType,
|
||||
UpdateViewSlugOperationType,
|
||||
UpdateViewSortOperationType,
|
||||
|
@ -947,7 +946,7 @@ class ViewHandler(metaclass=baserow_trace_methods(tracer)):
|
|||
|
||||
:param user: The user on whose behalf the view is updated.
|
||||
:param view: The view instance that needs to be updated.
|
||||
:param data: The fields that need to be updated.
|
||||
:param data: The properties that need to be updated.
|
||||
:raises ValueError: When the provided view not an instance of View.
|
||||
:return: The updated view instance.
|
||||
"""
|
||||
|
@ -955,16 +954,12 @@ class ViewHandler(metaclass=baserow_trace_methods(tracer)):
|
|||
if not isinstance(view, View):
|
||||
raise ValueError("The view is not an instance of View.")
|
||||
|
||||
workspace = view.table.database.workspace
|
||||
CoreHandler().check_permissions(
|
||||
user, UpdateViewOperationType.type, workspace=workspace, context=view
|
||||
)
|
||||
view_type = view_type_registry.get_by_model(view)
|
||||
view_type.check_view_update_permissions(user, view, data)
|
||||
view_type.before_view_update(data, view, user)
|
||||
|
||||
old_view = deepcopy(view)
|
||||
|
||||
view_type = view_type_registry.get_by_model(view)
|
||||
view_type.before_view_update(data, view, user)
|
||||
|
||||
view_values = view_type.prepare_values(data, view.table, user)
|
||||
allowed_fields = [
|
||||
"name",
|
||||
|
@ -1003,6 +998,7 @@ class ViewHandler(metaclass=baserow_trace_methods(tracer)):
|
|||
)
|
||||
view = set_allowed_attrs(view_values, allowed_attrs, view)
|
||||
if previous_public_value != view.public:
|
||||
workspace = view.table.database.workspace
|
||||
CoreHandler().check_permissions(
|
||||
user,
|
||||
UpdateViewPublicOperationType.type,
|
||||
|
|
|
@ -6,7 +6,9 @@ from django.dispatch import receiver
|
|||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import ngettext
|
||||
|
||||
from baserow.contrib.database.views.operations import UpdateViewOperationType
|
||||
from baserow.contrib.database.views.operations import (
|
||||
CanReceiveNotificationOnSubmitFormViewOperationType,
|
||||
)
|
||||
from baserow.core.handler import CoreHandler
|
||||
from baserow.core.notifications.handler import NotificationHandler
|
||||
from baserow.core.notifications.registries import (
|
||||
|
@ -116,7 +118,7 @@ def create_form_submitted_notification(sender, form, row, values, user, **kwargs
|
|||
# Ensure all users still have permissions on the table to see the notification
|
||||
allowed_users = CoreHandler().check_permission_for_multiple_actors(
|
||||
users_to_notify,
|
||||
UpdateViewOperationType.type,
|
||||
CanReceiveNotificationOnSubmitFormViewOperationType.type,
|
||||
workspace=form.table.database.workspace,
|
||||
context=form,
|
||||
)
|
||||
|
|
|
@ -124,6 +124,10 @@ class UpdateViewOperationType(ViewOperationType):
|
|||
type = "database.table.view.update"
|
||||
|
||||
|
||||
class CanReceiveNotificationOnSubmitFormViewOperationType(ViewOperationType):
|
||||
type = "database.table.view.can_receive_notification_on_submit_form_view"
|
||||
|
||||
|
||||
class DeleteViewOperationType(ViewOperationType):
|
||||
type = "database.table.view.delete"
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ from rest_framework.serializers import Serializer
|
|||
|
||||
from baserow.contrib.database.fields.field_filters import OptionallyAnnotatedQ
|
||||
from baserow.core.exceptions import PermissionDenied
|
||||
from baserow.core.handler import CoreHandler
|
||||
from baserow.core.models import Workspace, WorkspaceUser
|
||||
from baserow.core.registries import OperationType
|
||||
from baserow.core.registry import (
|
||||
|
@ -837,6 +838,29 @@ class ViewType(
|
|||
},
|
||||
)
|
||||
|
||||
def check_view_update_permissions(
|
||||
self, user: AbstractUser, view: "View", data: Dict[str, Any]
|
||||
):
|
||||
"""
|
||||
Hook that's called just before a view is updated. By default, it checks the
|
||||
`UpdateViewOperationType`, but when overwritten, it can optionally check for
|
||||
different permissions depending on the data. It returns nothing if the user has
|
||||
permissions, or raises a PermissionDenied error otherwise.
|
||||
|
||||
:param user: The user on whose behalf the view is updated.
|
||||
:param view: The view instance that needs to be updated.
|
||||
:param data: The properties that need to be updated.
|
||||
:raises PermissionDenied: if the user doesn't have permissions to update the
|
||||
view.
|
||||
"""
|
||||
|
||||
from .operations import UpdateViewOperationType
|
||||
|
||||
workspace = view.table.database.workspace
|
||||
CoreHandler().check_permissions(
|
||||
user, UpdateViewOperationType.type, workspace=workspace, context=view
|
||||
)
|
||||
|
||||
|
||||
class ViewTypeRegistry(
|
||||
APIUrlsRegistryMixin, CustomFieldsRegistryMixin, ModelRegistryMixin, Registry
|
||||
|
|
|
@ -46,6 +46,7 @@ from baserow.contrib.database.fields.models import Field, FileField, SelectOptio
|
|||
from baserow.contrib.database.fields.registries import field_type_registry
|
||||
from baserow.contrib.database.table.models import Table
|
||||
from baserow.contrib.database.views.registries import view_aggregation_type_registry
|
||||
from baserow.core.handler import CoreHandler
|
||||
from baserow.core.import_export.utils import file_chunk_generator
|
||||
from baserow.core.storage import ExportZipFile
|
||||
from baserow.core.user_files.handler import UserFileHandler
|
||||
|
@ -1403,3 +1404,26 @@ class FormViewType(ViewType):
|
|||
return FormViewFieldOptions(
|
||||
field_id=field_id, form_view_id=view.id, enabled=False
|
||||
)
|
||||
|
||||
def check_view_update_permissions(self, user, view, data):
|
||||
from .operations import CanReceiveNotificationOnSubmitFormViewOperationType
|
||||
|
||||
workspace = view.table.database.workspace
|
||||
|
||||
if "receive_notification_on_submit" in data:
|
||||
# If `receive_notification_on_submit` is in the data, then we must check if
|
||||
# the user has permissions to receive a notification on submit.
|
||||
CoreHandler().check_permissions(
|
||||
user,
|
||||
CanReceiveNotificationOnSubmitFormViewOperationType.type,
|
||||
workspace=workspace,
|
||||
context=view,
|
||||
)
|
||||
|
||||
# If only the `receive_notification_on_submit` is provided, then there is
|
||||
# no need to check if the user has permissions to update the view because
|
||||
# nothing else is changed.
|
||||
if len(data) == 1:
|
||||
return
|
||||
|
||||
return super().check_view_update_permissions(user, view, data)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "bug",
|
||||
"message": "Allow editors to subscribe to a form view.",
|
||||
"issue_number": 3271,
|
||||
"bullet_points": [],
|
||||
"created_at": "2025-01-18"
|
||||
}
|
|
@ -126,6 +126,7 @@ from baserow.contrib.database.tokens.operations import (
|
|||
UseTokenOperationType,
|
||||
)
|
||||
from baserow.contrib.database.views.operations import (
|
||||
CanReceiveNotificationOnSubmitFormViewOperationType,
|
||||
CreateAndUsePersonalViewOperationType,
|
||||
CreatePublicViewOperationType,
|
||||
CreateViewDecorationOperationType,
|
||||
|
@ -347,6 +348,7 @@ default_roles[EDITOR_ROLE_UID].extend(
|
|||
RestoreDatabaseRowOperationType,
|
||||
ListTeamSubjectsOperationType,
|
||||
ReadTeamSubjectOperationType,
|
||||
CanReceiveNotificationOnSubmitFormViewOperationType,
|
||||
]
|
||||
)
|
||||
default_roles[BUILDER_ROLE_UID].extend(
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
from django.test import override_settings
|
||||
|
||||
import pytest
|
||||
|
||||
from baserow.contrib.database.views.handler import ViewHandler
|
||||
from baserow.core.exceptions import PermissionDenied
|
||||
from baserow_enterprise.role.handler import RoleAssignmentHandler
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@override_settings(DEBUG=True)
|
||||
def test_update_form_view_as_editor_fails(enterprise_data_fixture):
|
||||
enterprise_data_fixture.enable_enterprise()
|
||||
user, token = enterprise_data_fixture.create_user_and_token(
|
||||
email="test@test.nl", password="password", first_name="Test1"
|
||||
)
|
||||
table = enterprise_data_fixture.create_database_table(user)
|
||||
form = enterprise_data_fixture.create_form_view(table=table)
|
||||
editor_role = RoleAssignmentHandler().get_role_by_uid("EDITOR")
|
||||
RoleAssignmentHandler().assign_role(
|
||||
user, table.database.workspace, role=editor_role, scope=table
|
||||
)
|
||||
|
||||
handler = ViewHandler()
|
||||
|
||||
with pytest.raises(PermissionDenied):
|
||||
handler.update_view(user=user, view=form, name="Test 1")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@override_settings(DEBUG=True)
|
||||
def test_update_form_view_notification_as_editor_succeeds(enterprise_data_fixture):
|
||||
enterprise_data_fixture.enable_enterprise()
|
||||
user, token = enterprise_data_fixture.create_user_and_token(
|
||||
email="test@test.nl", password="password", first_name="Test1"
|
||||
)
|
||||
table = enterprise_data_fixture.create_database_table(user)
|
||||
form = enterprise_data_fixture.create_form_view(table=table)
|
||||
editor_role = RoleAssignmentHandler().get_role_by_uid("EDITOR")
|
||||
RoleAssignmentHandler().assign_role(
|
||||
user, table.database.workspace, role=editor_role, scope=table
|
||||
)
|
||||
|
||||
handler = ViewHandler()
|
||||
handler.update_view(user=user, view=form, receive_notification_on_submit=True)
|
||||
assert form.users_to_notify_on_submit.count() == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@override_settings(DEBUG=True)
|
||||
def test_update_form_view_and_notification_as_editor_fails(enterprise_data_fixture):
|
||||
enterprise_data_fixture.enable_enterprise()
|
||||
user, token = enterprise_data_fixture.create_user_and_token(
|
||||
email="test@test.nl", password="password", first_name="Test1"
|
||||
)
|
||||
table = enterprise_data_fixture.create_database_table(user)
|
||||
form = enterprise_data_fixture.create_form_view(table=table)
|
||||
editor_role = RoleAssignmentHandler().get_role_by_uid("EDITOR")
|
||||
RoleAssignmentHandler().assign_role(
|
||||
user, table.database.workspace, role=editor_role, scope=table
|
||||
)
|
||||
|
||||
handler = ViewHandler()
|
||||
|
||||
with pytest.raises(PermissionDenied):
|
||||
handler.update_view(
|
||||
user=user, view=form, receive_notification_on_submit=True, name="Test"
|
||||
)
|
|
@ -9,6 +9,7 @@ from baserow_premium.views.models import OWNERSHIP_TYPE_PERSONAL
|
|||
|
||||
from baserow.contrib.database.table.models import Table
|
||||
from baserow.contrib.database.views.operations import (
|
||||
CanReceiveNotificationOnSubmitFormViewOperationType,
|
||||
CreateAndUsePersonalViewOperationType,
|
||||
CreateViewDecorationOperationType,
|
||||
CreateViewFilterGroupOperationType,
|
||||
|
@ -91,6 +92,7 @@ class ViewOwnershipPermissionManagerType(PermissionManagerType):
|
|||
DeleteViewSortOperationType.type,
|
||||
ReadViewOperationType.type,
|
||||
UpdateViewOperationType.type,
|
||||
CanReceiveNotificationOnSubmitFormViewOperationType.type,
|
||||
DeleteViewOperationType.type,
|
||||
DuplicateViewOperationType.type,
|
||||
CreateViewFilterOperationType.type,
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
<template>
|
||||
<div class="form-view__meta-controls">
|
||||
<SwitchInput
|
||||
v-if="
|
||||
$hasPermission(
|
||||
'database.table.view.can_receive_notification_on_submit_form_view',
|
||||
view,
|
||||
database.workspace.id
|
||||
)
|
||||
"
|
||||
small
|
||||
:value="view.receive_notification_on_submit"
|
||||
class="margin-bottom-3"
|
||||
|
|
Loading…
Add table
Reference in a new issue