Fix: respect global permissions for UI settings (#5919)

This commit is contained in:
shamoon 2024-02-26 12:19:31 -08:00 committed by GitHub
parent f5e1675107
commit d2f9b5d5e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 58 additions and 5 deletions

View File

@ -163,7 +163,7 @@ export const routes: Routes = [
canActivate: [PermissionsGuard],
data: {
requiredPermission: {
action: PermissionAction.View,
action: PermissionAction.Change,
type: PermissionType.UISettings,
},
},

View File

@ -351,5 +351,5 @@
<div [ngbNavOutlet]="nav" class="border-start border-end border-bottom p-3 mb-3 shadow-sm"></div>
<button type="submit" class="btn btn-primary mb-2" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.UISettings }" [disabled]="(isDirty$ | async) === false" i18n>Save</button>
<button type="submit" class="btn btn-primary mb-2" [disabled]="(isDirty$ | async) === false" i18n>Save</button>
</form>

View File

@ -55,7 +55,7 @@
<i-bs class="me-2" name="person"></i-bs>&nbsp;<ng-container i18n>My Profile</ng-container>
</button>
<a ngbDropdownItem class="nav-link" routerLink="settings" (click)="closeMenu()"
*pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.UISettings }">
*pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.UISettings }">
<i-bs class="me-2" name="gear"></i-bs><ng-container i18n>Settings</ng-container>
</a>
<a ngbDropdownItem class="nav-link d-flex" href="accounts/logout/" (click)="onLogout()">
@ -227,7 +227,7 @@
<span i18n>Administration</span>
</h6>
<ul class="nav flex-column mb-2">
<li class="nav-item" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.UISettings }"
<li class="nav-item" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.UISettings }"
tourAnchor="tour.settings">
<a class="nav-link" routerLink="settings" routerLinkActive="active" (click)="closeMenu()"
ngbPopover="Settings" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"

View File

@ -1,5 +1,6 @@
import json
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from rest_framework import status
from rest_framework.test import APITestCase
@ -65,3 +66,47 @@ class TestApiUiSettings(DirectoriesMixin, APITestCase):
ui_settings.settings,
settings["settings"],
)
def test_api_set_ui_settings_insufficient_global_permissions(self):
not_superuser = User.objects.create_user(username="test_not_superuser")
self.client.force_authenticate(user=not_superuser)
settings = {
"settings": {
"dark_mode": {
"enabled": True,
},
},
}
response = self.client.post(
self.ENDPOINT,
json.dumps(settings),
content_type="application/json",
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_api_set_ui_settings_sufficient_global_permissions(self):
not_superuser = User.objects.create_user(username="test_not_superuser")
not_superuser.user_permissions.add(
*Permission.objects.filter(codename__contains="uisettings"),
)
not_superuser.save()
self.client.force_authenticate(user=not_superuser)
settings = {
"settings": {
"dark_mode": {
"enabled": True,
},
},
}
response = self.client.post(
self.ENDPOINT,
json.dumps(settings),
content_type="application/json",
)
self.assertEqual(response.status_code, status.HTTP_200_OK)

View File

@ -51,6 +51,7 @@ from rest_framework.mixins import DestroyModelMixin
from rest_framework.mixins import ListModelMixin
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.mixins import UpdateModelMixin
from rest_framework.permissions import DjangoModelPermissions
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
@ -103,6 +104,7 @@ from documents.models import SavedView
from documents.models import ShareLink
from documents.models import StoragePath
from documents.models import Tag
from documents.models import UiSettings
from documents.models import Workflow
from documents.models import WorkflowAction
from documents.models import WorkflowTrigger
@ -1190,9 +1192,15 @@ class StoragePathViewSet(ModelViewSet, PassUserMixin):
class UiSettingsView(GenericAPIView):
permission_classes = (IsAuthenticated,)
queryset = UiSettings.objects.all()
permission_classes = (IsAuthenticated, DjangoModelPermissions)
serializer_class = UiSettingsViewSerializer
perms_map = {
"GET": ["%(app_label)s.view_%(model_name)s"],
"POST": ["%(app_label)s.change_%(model_name)s"],
}
def get(self, request, format=None):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)