mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add hook to update group permission roles
(doesn't do anything yet)
This commit is contained in:
parent
bedda66949
commit
16f1b4c784
@ -11,6 +11,20 @@ from django.contrib.auth.models import Group
|
|||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
from users.models import RuleSet
|
||||||
|
|
||||||
|
|
||||||
|
class RuleSetInline(admin.TabularInline):
|
||||||
|
model = RuleSet
|
||||||
|
can_delete = False
|
||||||
|
verbose_name = 'Ruleset'
|
||||||
|
verbose_plural_name = 'Rulesets'
|
||||||
|
fields = ['name'] + [option for option in RuleSet.RULE_OPTIONS]
|
||||||
|
readonly_fields = ['name']
|
||||||
|
max_num = len(RuleSet.RULESET_CHOICES)
|
||||||
|
min_num = 1
|
||||||
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
class InvenTreeGroupAdminForm(forms.ModelForm):
|
class InvenTreeGroupAdminForm(forms.ModelForm):
|
||||||
|
|
||||||
@ -18,6 +32,7 @@ class InvenTreeGroupAdminForm(forms.ModelForm):
|
|||||||
model = Group
|
model = Group
|
||||||
exclude = []
|
exclude = []
|
||||||
fields = [
|
fields = [
|
||||||
|
'name',
|
||||||
'users',
|
'users',
|
||||||
'permissions',
|
'permissions',
|
||||||
]
|
]
|
||||||
@ -35,6 +50,7 @@ class InvenTreeGroupAdminForm(forms.ModelForm):
|
|||||||
required=False,
|
required=False,
|
||||||
widget=FilteredSelectMultiple('users', False),
|
widget=FilteredSelectMultiple('users', False),
|
||||||
label=_('Users'),
|
label=_('Users'),
|
||||||
|
help_text=_('Select which users are assigned to this group')
|
||||||
)
|
)
|
||||||
|
|
||||||
def save_m2m(self):
|
def save_m2m(self):
|
||||||
@ -59,8 +75,31 @@ class RoleGroupAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
form = InvenTreeGroupAdminForm
|
form = InvenTreeGroupAdminForm
|
||||||
|
|
||||||
|
inlines = [
|
||||||
|
RuleSetInline,
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_formsets_with_inlines(self, request, obj=None):
|
||||||
|
for inline in self.get_inline_instances(request, obj):
|
||||||
|
# Hide RuleSetInline in the 'Add role' view
|
||||||
|
if not isinstance(inline, RuleSetInline) or obj is not None:
|
||||||
|
yield inline.get_formset(request, obj), inline
|
||||||
|
|
||||||
filter_horizontal = ['permissions']
|
filter_horizontal = ['permissions']
|
||||||
|
|
||||||
|
# Save inlines before model
|
||||||
|
# https://stackoverflow.com/a/14860703/12794913
|
||||||
|
def save_model(self, request, obj, form, change):
|
||||||
|
if obj is not None:
|
||||||
|
# Save model immediately only if in 'Add role' view
|
||||||
|
super().save_model(request, obj, form, change)
|
||||||
|
else:
|
||||||
|
pass # don't actually save the parent instance
|
||||||
|
|
||||||
|
def save_formset(self, request, form, formset, change):
|
||||||
|
formset.save() # this will save the children
|
||||||
|
form.instance.save() # form.instance is the parent
|
||||||
|
|
||||||
|
|
||||||
admin.site.unregister(Group)
|
admin.site.unregister(Group)
|
||||||
admin.site.register(Group, RoleGroupAdmin)
|
admin.site.register(Group, RoleGroupAdmin)
|
||||||
|
@ -1,8 +1,33 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db.utils import OperationalError, ProgrammingError
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class UsersConfig(AppConfig):
|
class UsersConfig(AppConfig):
|
||||||
name = 'users'
|
name = 'users'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.assign_permissions()
|
||||||
|
except (OperationalError, ProgrammingError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def assign_permissions(self):
|
||||||
|
|
||||||
|
from django.contrib.auth.models import Group
|
||||||
|
from users.models import RuleSet, update_group_roles
|
||||||
|
|
||||||
|
# First, delete any rule_set objects which have become outdated!
|
||||||
|
for rule in RuleSet.objects.all():
|
||||||
|
if rule.name not in RuleSet.RULESET_NAMES:
|
||||||
|
print("need to delete:", rule.name)
|
||||||
|
rule.delete()
|
||||||
|
|
||||||
|
# Update group permission assignments for all groups
|
||||||
|
for group in Group.objects.all():
|
||||||
|
|
||||||
|
update_group_roles(group)
|
@ -1 +1,160 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from django.contrib.auth.models import Group
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
|
||||||
|
|
||||||
|
class RuleSet(models.Model):
|
||||||
|
"""
|
||||||
|
A RuleSet is somewhat like a superset of the django permission class,
|
||||||
|
in that in encapsulates a bunch of permissions.
|
||||||
|
|
||||||
|
There are *many* apps models used within InvenTree,
|
||||||
|
so it makes sense to group them into "roles".
|
||||||
|
|
||||||
|
These roles translate (roughly) to the menu options available.
|
||||||
|
|
||||||
|
Each role controls permissions for a number of database tables,
|
||||||
|
which are then handled using the normal django permissions approach.
|
||||||
|
"""
|
||||||
|
|
||||||
|
RULESET_CHOICES = [
|
||||||
|
('general', _('General')),
|
||||||
|
('admin', _('Admin')),
|
||||||
|
('part', _('Parts')),
|
||||||
|
('stock', _('Stock')),
|
||||||
|
('build', _('Build Orders')),
|
||||||
|
('supplier', _('Suppliers')),
|
||||||
|
('purchase_order', _('Purchase Orders')),
|
||||||
|
('customer', _('Customers')),
|
||||||
|
('sales_order', _('Sales Orders')),
|
||||||
|
]
|
||||||
|
|
||||||
|
RULESET_NAMES = [
|
||||||
|
choice[0] for choice in RULESET_CHOICES
|
||||||
|
]
|
||||||
|
|
||||||
|
RULESET_MODELS = {
|
||||||
|
'general': [
|
||||||
|
'part.partstar',
|
||||||
|
],
|
||||||
|
'admin': [
|
||||||
|
'auth.group',
|
||||||
|
'auth.user',
|
||||||
|
'auth.permission',
|
||||||
|
'authtoken.token',
|
||||||
|
],
|
||||||
|
'part': [
|
||||||
|
'part.part',
|
||||||
|
'part.bomitem',
|
||||||
|
'part.partcategory',
|
||||||
|
'part.partattachment',
|
||||||
|
'part.partsellpricebreak',
|
||||||
|
'part.parttesttemplate',
|
||||||
|
'part.partparametertemplate',
|
||||||
|
'part.partparameter',
|
||||||
|
],
|
||||||
|
'stock': [
|
||||||
|
'stock.stockitem',
|
||||||
|
'stock.stocklocation',
|
||||||
|
'stock.stockitemattachment',
|
||||||
|
'stock.stockitemtracking',
|
||||||
|
'stock.stockitemtestresult',
|
||||||
|
],
|
||||||
|
'build': [
|
||||||
|
'part.part',
|
||||||
|
'part.partcategory',
|
||||||
|
'part.bomitem',
|
||||||
|
'build.build',
|
||||||
|
'build.builditem',
|
||||||
|
'stock.stockitem',
|
||||||
|
'stock.stocklocation',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
RULE_OPTIONS = [
|
||||||
|
'can_view',
|
||||||
|
'can_add',
|
||||||
|
'can_change',
|
||||||
|
'can_delete',
|
||||||
|
]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = (
|
||||||
|
('name', 'group'),
|
||||||
|
)
|
||||||
|
|
||||||
|
name = models.CharField(
|
||||||
|
max_length=50,
|
||||||
|
choices=RULESET_CHOICES,
|
||||||
|
blank=False,
|
||||||
|
help_text=_('Permission set')
|
||||||
|
)
|
||||||
|
|
||||||
|
group = models.ForeignKey(
|
||||||
|
Group,
|
||||||
|
related_name='rule_sets',
|
||||||
|
blank=False, null=False,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
help_text=_('Group'),
|
||||||
|
)
|
||||||
|
|
||||||
|
can_view = models.BooleanField(verbose_name=_('View'), default=True, help_text=_('Permission to view items'))
|
||||||
|
|
||||||
|
can_add = models.BooleanField(verbose_name=_('Create'), default=False, help_text=_('Permission to add items'))
|
||||||
|
|
||||||
|
can_change = models.BooleanField(verbose_name=_('Update'), default=False, help_text=_('Permissions to edit items'))
|
||||||
|
|
||||||
|
can_delete = models.BooleanField(verbose_name=_('Delete'), default=False, help_text=_('Permission to delete items'))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_models(self):
|
||||||
|
|
||||||
|
models = {
|
||||||
|
''
|
||||||
|
}
|
||||||
|
|
||||||
|
def update_group_roles(group):
|
||||||
|
"""
|
||||||
|
Update group roles:
|
||||||
|
|
||||||
|
a) Ensure default roles are assigned to each group.
|
||||||
|
b) Ensure group permissions are correctly updated and assigned
|
||||||
|
"""
|
||||||
|
|
||||||
|
# List of permissions which must be added to the group
|
||||||
|
permissions_to_add = []
|
||||||
|
|
||||||
|
# List of permissions which must be removed from the group
|
||||||
|
permissions_to_delete = []
|
||||||
|
|
||||||
|
# Get all the rulesets associated with this group
|
||||||
|
for r in RuleSet.RULESET_CHOICES:
|
||||||
|
|
||||||
|
rulename = r[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
ruleset = RuleSet.objects.get(group=group, name=rulename)
|
||||||
|
except RuleSet.DoesNotExist:
|
||||||
|
# Create the ruleset with default values (if it does not exist)
|
||||||
|
ruleset = RuleSet.objects.create(group=group, name=rulename)
|
||||||
|
|
||||||
|
# TODO - Update permissions here
|
||||||
|
|
||||||
|
# TODO - Update group permissions
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=Group)
|
||||||
|
def create_missing_rule_sets(sender, instance, **kwargs):
|
||||||
|
|
||||||
|
update_group_roles(instance)
|
Loading…
Reference in New Issue
Block a user