From b686cc13275c3b6bfb8c85629debbe0bfa2ad60f Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 23 Apr 2026 11:25:43 +1000 Subject: [PATCH] Model permission tweaks (#11788) * Model permission tweaks * Update CHANGELOG * Update plugin docs * Add warning --- CHANGELOG.md | 1 + docs/docs/plugins/mixins/app.md | 24 ++++++++++++++++++++++ src/backend/InvenTree/users/permissions.py | 5 +++++ 3 files changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2be3883c45..d36d4c7cd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#11778](https://github.com/inventree/InvenTree/pull/11778) adds inline supplier part creation to po line item addition dialog. - [#11772](https://github.com/inventree/InvenTree/pull/11772) the UI now warns if you navigate away from a note panel with unsaved changes +- [#11788](https://github.com/inventree/InvenTree/pull/11788) adds support for custom permissions checks on database models defined in plugins. If a model defines a `check_user_permission` classmethod, this will be called to determine if a user has permission to view the model. This is required for plugin models which do not have the required ruleset definitions for the standard permission system. ### Changed diff --git a/docs/docs/plugins/mixins/app.md b/docs/docs/plugins/mixins/app.md index e607bc7b52..895341d4c6 100644 --- a/docs/docs/plugins/mixins/app.md +++ b/docs/docs/plugins/mixins/app.md @@ -8,3 +8,27 @@ If this mixin is added to a plugin the directory the plugin class is defined in !!! warning "Danger Zone" Only use this mixin if you have an understanding of Django's [app system]({% include "django.html" %}/ref/applications). Plugins with this mixin are deeply integrated into InvenTree and can cause difficult to reproduce or long-running errors. Use the built-in testing functions of Django to make sure your code does not cause unwanted behaviour in InvenTree before releasing. + +## Custom Models + +This mixin allows you to define custom database models within your plugin. These models will be automatically registered with the InvenTree server, and will be available for use within your plugin code. + +### Model Permissions + +Some database operations within the InvenTree ecosystem may require custom permissions checks - to determine which actions a user can perform against a given model. If your plugin defines custom models, you may need to implement a custom permission check method on your model class. + +Each model class can implement a `check_user_permission` classmethod, which will be called by the InvenTree permission system when checking permissions for that model. This method should return `True` if the user has the required permissions, and `False` otherwise. + + +```python +class MyCustomModel(models.Model): + # model fields here + + @classmethod + def check_user_permission(cls, user: User, permission: str) -> bool: + # custom permission logic here + return True # or False +``` + +!!! warning "Default Permissions" + By default, if the `check_user_permission` method is not implemented, the InvenTree permission system will return `False` for all permission checks against that model. This is to ensure that no permissions are granted by default, and that the plugin developer must explicitly define the required permissions for their custom models. diff --git a/src/backend/InvenTree/users/permissions.py b/src/backend/InvenTree/users/permissions.py index 7c93f5ec97..c3d7c964b1 100644 --- a/src/backend/InvenTree/users/permissions.py +++ b/src/backend/InvenTree/users/permissions.py @@ -195,6 +195,11 @@ def check_user_permission( result = user.has_perm(permission_name) + # If the user does not have permissions (as determined above), check if the model class provides a custom permission check method + # This is required for non-standard models (i.e. defined via plugins), which do not have the required ruleset definitions + if not result and hasattr(model, 'check_user_permission'): # pragma: no cover + result = model.check_user_permission(user, permission) + # Save result to session-cache InvenTree.cache.set_session_cache(cache_key, result)