Compare commits

...

4 Commits

Author SHA1 Message Date
dependabot[bot]
d7b2e002ce
docker(deps): bump astral-sh/uv (#10084)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.7.8-python3.12-bookworm-slim to 0.7.9-python3.12-bookworm-slim.
- [Release notes](https://github.com/astral-sh/uv/releases)
- [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/uv/compare/0.7.8...0.7.9)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.7.9-python3.12-bookworm-slim
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-31 09:27:59 -07:00
Trenton H
51e70f0a20
Removes the reviewers field, excludes Django and related from the small changes group (#10076) 2025-05-31 15:35:51 +00:00
mamasch19
bd257925bd
Documentation: fix typo in configuration.md (#10077) 2025-05-29 15:18:30 -07:00
shamoon
15b1b83c66
Chore/fix: cleanup user or group references in settings upon deletion (#10049) 2025-05-29 19:05:48 +00:00
5 changed files with 126 additions and 15 deletions

View File

@ -16,9 +16,6 @@ updates:
labels:
- "frontend"
- "dependencies"
# Add reviewers
reviewers:
- "paperless-ngx/frontend"
groups:
frontend-angular-dependencies:
patterns:
@ -44,9 +41,6 @@ updates:
labels:
- "backend"
- "dependencies"
# Add reviewers
reviewers:
- "paperless-ngx/backend"
groups:
development:
patterns:
@ -65,6 +59,9 @@ updates:
update-types:
- "minor"
- "patch"
exclude-patterns:
- "*django*"
- "drf-*"
pre-built:
patterns:
- psycopg*
@ -79,9 +76,6 @@ updates:
labels:
- "ci-cd"
- "dependencies"
# Add reviewers
reviewers:
- "paperless-ngx/ci-cd"
groups:
actions:
update-types:
@ -94,8 +88,6 @@ updates:
schedule:
interval: "weekly"
open-pull-requests-limit: 5
reviewers:
- "paperless-ngx/ci-cd"
labels:
- "dependencies"
commit-message:
@ -107,8 +99,6 @@ updates:
schedule:
interval: "weekly"
open-pull-requests-limit: 5
reviewers:
- "paperless-ngx/ci-cd"
labels:
- "dependencies"
commit-message:

View File

@ -32,7 +32,7 @@ RUN set -eux \
# Purpose: Installs s6-overlay and rootfs
# Comments:
# - Don't leave anything extra in here either
FROM ghcr.io/astral-sh/uv:0.7.8-python3.12-bookworm-slim AS s6-overlay-base
FROM ghcr.io/astral-sh/uv:0.7.9-python3.12-bookworm-slim AS s6-overlay-base
WORKDIR /usr/src/s6

View File

@ -200,7 +200,7 @@ and watch out for indentation if editing the YAML file.
### Email Parsing
#### [`PAPERLESS_EMAIL_PARSE_DEFAULT_LAYOUT=<int>`(#PAPERLESS_EMAIL_PARSE_DEFAULT_LAYOUT) {#PAPERLESS_EMAIL_PARSE_DEFAULT_LAYOUT}
#### [`PAPERLESS_EMAIL_PARSE_DEFAULT_LAYOUT=<int>`](#PAPERLESS_EMAIL_PARSE_DEFAULT_LAYOUT) {#PAPERLESS_EMAIL_PARSE_DEFAULT_LAYOUT}
: The default layout to use for emails that are consumed as documents. Must be one of the integer choices below. Note that mail
rules can specify this setting, thus this fallback is used for the default selection and for .eml files consumed by other means.

View File

@ -13,6 +13,7 @@ from celery.signals import task_failure
from celery.signals import task_postrun
from celery.signals import task_prerun
from django.conf import settings
from django.contrib.auth.models import Group
from django.contrib.auth.models import User
from django.db import DatabaseError
from django.db import close_old_connections
@ -38,6 +39,7 @@ from documents.models import MatchingModel
from documents.models import PaperlessTask
from documents.models import SavedView
from documents.models import Tag
from documents.models import UiSettings
from documents.models import Workflow
from documents.models import WorkflowAction
from documents.models import WorkflowRun
@ -581,6 +583,51 @@ def cleanup_custom_field_deletion(sender, instance: CustomField, **kwargs):
)
@receiver(models.signals.post_delete, sender=User)
@receiver(models.signals.post_delete, sender=Group)
def cleanup_user_deletion(sender, instance: User | Group, **kwargs):
"""
When a user or group is deleted, remove non-cascading references.
At the moment, just the default permission settings in UiSettings.
"""
# Remove the user permission settings e.g.
# DEFAULT_PERMS_OWNER: 'general-settings:permissions:default-owner',
# DEFAULT_PERMS_VIEW_USERS: 'general-settings:permissions:default-view-users',
# DEFAULT_PERMS_VIEW_GROUPS: 'general-settings:permissions:default-view-groups',
# DEFAULT_PERMS_EDIT_USERS: 'general-settings:permissions:default-edit-users',
# DEFAULT_PERMS_EDIT_GROUPS: 'general-settings:permissions:default-edit-groups',
for ui_settings in UiSettings.objects.all():
try:
permissions = ui_settings.settings.get("permissions", {})
updated = False
if isinstance(instance, User):
if permissions.get("default_owner") == instance.pk:
permissions["default_owner"] = None
updated = True
if instance.pk in permissions.get("default_view_users", []):
permissions["default_view_users"].remove(instance.pk)
updated = True
if instance.pk in permissions.get("default_change_users", []):
permissions["default_change_users"].remove(instance.pk)
updated = True
elif isinstance(instance, Group):
if instance.pk in permissions.get("default_view_groups", []):
permissions["default_view_groups"].remove(instance.pk)
updated = True
if instance.pk in permissions.get("default_change_groups", []):
permissions["default_change_groups"].remove(instance.pk)
updated = True
if updated:
ui_settings.settings["permissions"] = permissions
ui_settings.save(update_fields=["settings"])
except Exception as e:
logger.error(
f"Error while cleaning up user {instance.pk} ({instance.username}) from ui_settings: {e}"
if isinstance(instance, User)
else f"Error while cleaning up group {instance.pk} ({instance.name}) from ui_settings: {e}",
)
def add_to_index(sender, document, **kwargs):
from documents import index

View File

@ -6,6 +6,7 @@ from django.http import HttpRequest
from django.test import TestCase
from django.test import override_settings
from documents.models import UiSettings
from paperless.signals import handle_failed_login
from paperless.signals import handle_social_account_updated
@ -190,3 +191,76 @@ class TestSyncSocialLoginGroups(TestCase):
sociallogin=sociallogin,
)
self.assertEqual(list(user.groups.all()), [])
class TestUserGroupDeletionCleanup(TestCase):
"""
Test that when a user or group is deleted, references are cleaned up properly
from ui_settings
"""
def test_user_group_deletion_cleanup(self):
"""
GIVEN:
- Existing user
- Existing group
WHEN:
- The user is deleted
- The group is deleted
THEN:
- References in ui_settings are cleaned up
"""
user = User.objects.create_user(username="testuser")
user2 = User.objects.create_user(username="testuser2")
group = Group.objects.create(name="testgroup")
ui_settings = UiSettings.objects.create(
user=user,
settings={
"permissions": {
"default_owner": user2.id,
"default_view_users": [user2.id],
"default_change_users": [user2.id],
"default_view_groups": [group.id],
"default_change_groups": [group.id],
},
},
)
user2.delete()
ui_settings.refresh_from_db()
permissions = ui_settings.settings.get("permissions", {})
self.assertIsNone(permissions.get("default_owner"))
self.assertEqual(permissions.get("default_view_users"), [])
self.assertEqual(permissions.get("default_change_users"), [])
group.delete()
ui_settings.refresh_from_db()
permissions = ui_settings.settings.get("permissions", {})
self.assertEqual(permissions.get("default_view_groups"), [])
self.assertEqual(permissions.get("default_change_groups"), [])
def test_user_group_deletion_error_handling(self):
"""
GIVEN:
- Existing user and group
WHEN:
- The user is deleted and an error occurs during the signal handling
THEN:
- Error is logged and the system remains stable
"""
user = User.objects.create_user(username="testuser")
user2 = User.objects.create_user(username="testuser2")
user2_id = user2.id
Group.objects.create(name="testgroup")
UiSettings.objects.create(
user=user,
) # invalid, no settings, this probably should not happen in production
with self.assertLogs("paperless.handlers", level="ERROR") as cm:
user2.delete()
self.assertIn(
f"Error while cleaning up user {user2_id}",
cm.output[0],
)