Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2021-03-02 22:08:33 +11:00
commit ab53764c81
9 changed files with 164 additions and 196 deletions

View File

@ -58,8 +58,10 @@ class RolePermission(permissions.BasePermission):
# Extract the model name associated with this request
model = view.serializer_class.Meta.model
# And the specific database table
table = model._meta.db_table
app_label = model._meta.app_label
model_name = model._meta.model_name
table = f"{app_label}_{model_name}"
except AttributeError:
# We will assume that if the serializer class does *not* have a Meta,
# then we don't need a permission

View File

@ -16,7 +16,7 @@ from django.urls import reverse_lazy
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views import View
from django.views.generic import UpdateView, CreateView, FormView
from django.views.generic import ListView, DetailView, CreateView, FormView, DeleteView, UpdateView
from django.views.generic.base import TemplateView
from part.models import Part, PartCategory
@ -113,14 +113,39 @@ class InvenTreeRoleMixin(PermissionRequiredMixin):
"""
Permission class based on user roles, not user 'permissions'.
To specify which role is required for the mixin,
set the class attribute 'role_required' to something like the following:
There are a number of ways that the permissions can be specified for a view:
role_required = 'part.add'
role_required = [
'part.change',
'build.add',
]
1. Specify the 'role_required' attribute (e.g. part.change)
2. Specify the 'permission_required' attribute (e.g. part.change_bomitem)
(Note: This is the "normal" django-esque way of doing this)
3. Do nothing. The mixin will attempt to "guess" what permission you require:
a) If there is a queryset associated with the View, we have the model!
b) The *type* of View tells us the permission level (e.g. AjaxUpdateView = change)
c) 1 + 1 = 3
d) Use the combination of model + permission as we would in 2)
1. Specify the 'role_required' attribute
=====================================
To specify which role is required for the mixin,
set the class attribute 'role_required' to something like the following:
role_required = 'part.add'
role_required = [
'part.change',
'build.add',
]
2. Specify the 'permission_required' attribute
===========================================
To specify a particular low-level permission,
set the class attribute 'permission_required' to something like:
permission_required = 'company.delete_company'
3. Do Nothing
==========
See above.
"""
# By default, no roles are required
@ -132,10 +157,6 @@ class InvenTreeRoleMixin(PermissionRequiredMixin):
Determine if the current user has specified permissions
"""
if self.permission_required:
# Ignore role-based permissions
return super().has_permission()
roles_required = []
if type(self.role_required) is str:
@ -163,9 +184,80 @@ class InvenTreeRoleMixin(PermissionRequiredMixin):
if not check_user_role(user, role, permission):
return False
# If a permission_required is specified, use that!
if self.permission_required:
# Ignore role-based permissions
return super().has_permission()
# Ok, so at this point we have not explicitly require a "role" or a "permission"
# Instead, we will use the model to introspect the data we need
model = getattr(self, 'model', None)
if not model:
queryset = getattr(self, 'queryset', None)
if queryset is not None:
model = queryset.model
# We were able to introspect a database model
if model is not None:
app_label = model._meta.app_label
model_name = model._meta.model_name
table = f"{app_label}_{model_name}"
permission = self.get_permission_class()
if not permission:
raise AttributeError(f"permission_class not defined for {type(self).__name__}")
# Check if the user has the required permission
return RuleSet.check_table_permission(user, table, permission)
# We did not fail any required checks
return True
def get_permission_class(self):
"""
Return the 'permission_class' required for the current View.
Must be one of:
- view
- change
- add
- delete
This can either be explicitly defined, by setting the
'permission_class' attribute,
or it can be "guessed" by looking at the type of class
"""
perm = getattr(self, 'permission_class', None)
# Permission is specified by the class itself
if perm:
return perm
# Otherwise, we will need to have a go at guessing...
permission_map = {
AjaxView: 'view',
ListView: 'view',
DetailView: 'view',
UpdateView: 'change',
DeleteView: 'delete',
AjaxUpdateView: 'change',
AjaxCreateView: 'add',
}
for view_class in permission_map.keys():
if issubclass(type(self), view_class):
return permission_map[view_class]
return None
class AjaxMixin(InvenTreeRoleMixin):
""" AjaxMixin provides basic functionality for rendering a Django form to JSON.

View File

@ -28,7 +28,6 @@ class BuildIndex(InvenTreeRoleMixin, ListView):
model = Build
template_name = 'build/index.html'
context_object_name = 'builds'
role_required = 'build.view'
def get_queryset(self):
""" Return all Build objects (order by date, newest first) """
@ -58,7 +57,6 @@ class BuildCancel(AjaxUpdateView):
ajax_form_title = _('Cancel Build')
context_object_name = 'build'
form_class = forms.CancelBuildForm
role_required = 'build.change'
def validate(self, build, form, **kwargs):
@ -92,7 +90,6 @@ class BuildAutoAllocate(AjaxUpdateView):
context_object_name = 'build'
ajax_form_title = _('Allocate Stock')
ajax_template_name = 'build/auto_allocate.html'
role_required = 'build.change'
def get_initial(self):
"""
@ -181,7 +178,6 @@ class BuildOutputCreate(AjaxUpdateView):
form_class = forms.BuildOutputCreateForm
ajax_template_name = 'build/build_output_create.html'
ajax_form_title = _('Create Build Output')
role_required = 'build.change'
def validate(self, build, form, **kwargs):
"""
@ -280,6 +276,7 @@ class BuildOutputDelete(AjaxUpdateView):
model = Build
form_class = forms.BuildOutputDeleteForm
ajax_form_title = _('Delete Build Output')
role_required = 'build.delete'
def get_initial(self):
@ -340,7 +337,6 @@ class BuildUnallocate(AjaxUpdateView):
form_class = forms.UnallocateBuildForm
ajax_form_title = _("Unallocate Stock")
ajax_template_name = "build/unallocate.html"
role_required = 'build.change'
def get_initial(self):
@ -408,7 +404,7 @@ class BuildComplete(AjaxUpdateView):
model = Build
form_class = forms.CompleteBuildForm
role_required = 'build.change'
ajax_form_title = _('Complete Build Order')
ajax_template_name = 'build/complete.html'
@ -444,7 +440,6 @@ class BuildOutputComplete(AjaxUpdateView):
context_object_name = "build"
ajax_form_title = _("Complete Build Output")
ajax_template_name = "build/complete_output.html"
role_required = 'build.change'
def get_form(self):
@ -579,13 +574,15 @@ class BuildOutputComplete(AjaxUpdateView):
}
class BuildNotes(UpdateView):
class BuildNotes(InvenTreeRoleMixin, UpdateView):
""" View for editing the 'notes' field of a Build object.
"""
context_object_name = 'build'
template_name = 'build/notes.html'
model = Build
# Override the default permission role for this View
role_required = 'build.view'
fields = ['notes']
@ -602,13 +599,12 @@ class BuildNotes(UpdateView):
return ctx
class BuildDetail(DetailView):
class BuildDetail(InvenTreeRoleMixin, DetailView):
""" Detail view of a single Build object. """
model = Build
template_name = 'build/detail.html'
context_object_name = 'build'
role_required = 'build.view'
def get_context_data(self, **kwargs):
@ -623,12 +619,11 @@ class BuildDetail(DetailView):
return ctx
class BuildAllocate(DetailView):
class BuildAllocate(InvenTreeRoleMixin, DetailView):
""" View for allocating parts to a Build """
model = Build
context_object_name = 'build'
template_name = 'build/allocate.html'
role_required = ['build.change']
def get_context_data(self, **kwargs):
""" Provide extra context information for the Build allocation page """
@ -652,13 +647,15 @@ class BuildAllocate(DetailView):
class BuildCreate(AjaxCreateView):
""" View to create a new Build object """
"""
View to create a new Build object
"""
model = Build
context_object_name = 'build'
form_class = forms.EditBuildForm
ajax_form_title = _('New Build Order')
ajax_template_name = 'modal_form.html'
role_required = 'build.add'
def get_form(self):
form = super().get_form()
@ -734,7 +731,6 @@ class BuildUpdate(AjaxUpdateView):
context_object_name = 'build'
ajax_form_title = _('Edit Build Order Details')
ajax_template_name = 'modal_form.html'
role_required = 'build.change'
def get_form(self):
@ -776,7 +772,6 @@ class BuildDelete(AjaxDeleteView):
model = Build
ajax_template_name = 'build/delete_build.html'
ajax_form_title = _('Delete Build Order')
role_required = 'build.delete'
class BuildItemDelete(AjaxDeleteView):
@ -788,7 +783,6 @@ class BuildItemDelete(AjaxDeleteView):
ajax_template_name = 'build/delete_build_item.html'
ajax_form_title = _('Unallocate Stock')
context_object_name = 'item'
role_required = 'build.delete'
def get_data(self):
return {
@ -805,7 +799,6 @@ class BuildItemCreate(AjaxCreateView):
form_class = forms.EditBuildItemForm
ajax_template_name = 'build/create_build_item.html'
ajax_form_title = _('Allocate stock to build output')
role_required = 'build.add'
# The output StockItem against which the allocation is being made
output = None
@ -1021,7 +1014,6 @@ class BuildItemEdit(AjaxUpdateView):
ajax_template_name = 'build/edit_build_item.html'
form_class = forms.EditBuildItemForm
ajax_form_title = _('Edit Stock Allocation')
role_required = 'build.change'
def get_data(self):
return {
@ -1055,7 +1047,6 @@ class BuildAttachmentCreate(AjaxCreateView):
model = BuildOrderAttachment
form_class = forms.EditBuildAttachmentForm
ajax_form_title = _('Add Build Order Attachment')
role_required = 'build.add'
def save(self, form, **kwargs):
"""
@ -1105,7 +1096,6 @@ class BuildAttachmentEdit(AjaxUpdateView):
model = BuildOrderAttachment
form_class = forms.EditBuildAttachmentForm
ajax_form_title = _('Edit Attachment')
role_required = 'build.change'
def get_form(self):
form = super().get_form()
@ -1127,7 +1117,6 @@ class BuildAttachmentDelete(AjaxDeleteView):
model = BuildOrderAttachment
ajax_form_title = _('Delete Attachment')
context_object_name = 'attachment'
role_required = 'build.delete'
def get_data(self):
return {

View File

@ -269,7 +269,6 @@ class SupplierPartEdit(AjaxUpdateView):
form_class = EditSupplierPartForm
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Supplier Part')
role_required = 'purchase_order.change'
def get_form(self):
form = super().get_form()
@ -294,7 +293,6 @@ class SupplierPartCreate(AjaxCreateView):
ajax_template_name = 'company/supplier_part_create.html'
ajax_form_title = _('Create new Supplier Part')
context_object_name = 'part'
role_required = 'purchase_order.add'
def validate(self, part, form):
@ -413,6 +411,7 @@ class SupplierPartDelete(AjaxDeleteView):
success_url = '/supplier/'
ajax_template_name = 'company/partdelete.html'
ajax_form_title = _('Delete Supplier Part')
role_required = 'purchase_order.delete'
parts = []
@ -485,7 +484,6 @@ class PriceBreakCreate(AjaxCreateView):
form_class = EditPriceBreakForm
ajax_form_title = _('Add Price Break')
ajax_template_name = 'modal_form.html'
role_required = 'purchase_order.add'
def get_data(self):
return {
@ -547,7 +545,6 @@ class PriceBreakEdit(AjaxUpdateView):
form_class = EditPriceBreakForm
ajax_form_title = _('Edit Price Break')
ajax_template_name = 'modal_form.html'
role_required = 'purchase_order.change'
def get_form(self):
@ -563,4 +560,3 @@ class PriceBreakDelete(AjaxDeleteView):
model = SupplierPriceBreak
ajax_form_title = _("Delete Price Break")
ajax_template_name = 'modal_delete_form.html'
role_required = 'purchase_order.delete'

View File

@ -44,8 +44,6 @@ class PurchaseOrderIndex(InvenTreeRoleMixin, ListView):
template_name = 'order/purchase_orders.html'
context_object_name = 'orders'
role_required = 'purchase_order.view'
def get_queryset(self):
""" Retrieve the list of purchase orders,
ensure that the most recent ones are returned first. """
@ -65,7 +63,6 @@ class SalesOrderIndex(InvenTreeRoleMixin, ListView):
model = SalesOrder
template_name = 'order/sales_orders.html'
context_object_name = 'orders'
role_required = 'sales_order.view'
class PurchaseOrderDetail(InvenTreeRoleMixin, DetailView):
@ -74,7 +71,6 @@ class PurchaseOrderDetail(InvenTreeRoleMixin, DetailView):
context_object_name = 'order'
queryset = PurchaseOrder.objects.all().prefetch_related('lines')
template_name = 'order/purchase_order_detail.html'
role_required = 'purchase_order.view'
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
@ -88,7 +84,6 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView):
context_object_name = 'order'
queryset = SalesOrder.objects.all().prefetch_related('lines')
template_name = 'order/sales_order_detail.html'
role_required = 'sales_order.view'
class PurchaseOrderAttachmentCreate(AjaxCreateView):
@ -100,7 +95,6 @@ class PurchaseOrderAttachmentCreate(AjaxCreateView):
form_class = order_forms.EditPurchaseOrderAttachmentForm
ajax_form_title = _("Add Purchase Order Attachment")
ajax_template_name = "modal_form.html"
role_required = 'purchase_order.add'
def save(self, form, **kwargs):
@ -150,7 +144,6 @@ class SalesOrderAttachmentCreate(AjaxCreateView):
model = SalesOrderAttachment
form_class = order_forms.EditSalesOrderAttachmentForm
ajax_form_title = _('Add Sales Order Attachment')
role_required = 'sales_order.add'
def save(self, form, **kwargs):
"""
@ -191,7 +184,6 @@ class PurchaseOrderAttachmentEdit(AjaxUpdateView):
model = PurchaseOrderAttachment
form_class = order_forms.EditPurchaseOrderAttachmentForm
ajax_form_title = _("Edit Attachment")
role_required = 'purchase_order.change'
def get_data(self):
return {
@ -213,7 +205,6 @@ class SalesOrderAttachmentEdit(AjaxUpdateView):
model = SalesOrderAttachment
form_class = order_forms.EditSalesOrderAttachmentForm
ajax_form_title = _("Edit Attachment")
role_required = 'sales_order.change'
def get_data(self):
return {
@ -235,7 +226,6 @@ class PurchaseOrderAttachmentDelete(AjaxDeleteView):
ajax_form_title = _("Delete Attachment")
ajax_template_name = "order/delete_attachment.html"
context_object_name = "attachment"
role_required = 'purchase_order.delete'
def get_data(self):
return {
@ -250,7 +240,6 @@ class SalesOrderAttachmentDelete(AjaxDeleteView):
ajax_form_title = _("Delete Attachment")
ajax_template_name = "order/delete_attachment.html"
context_object_name = "attachment"
role_required = 'sales_order.delete'
def get_data(self):
return {
@ -264,6 +253,8 @@ class PurchaseOrderNotes(InvenTreeRoleMixin, UpdateView):
context_object_name = 'order'
template_name = 'order/order_notes.html'
model = PurchaseOrder
# Override the default permission roles
role_required = 'purchase_order.view'
fields = ['notes']
@ -311,7 +302,6 @@ class PurchaseOrderCreate(AjaxCreateView):
model = PurchaseOrder
ajax_form_title = _("Create Purchase Order")
form_class = order_forms.EditPurchaseOrderForm
role_required = 'purchase_order.add'
def get_initial(self):
initials = super().get_initial().copy()
@ -347,7 +337,6 @@ class SalesOrderCreate(AjaxCreateView):
model = SalesOrder
ajax_form_title = _("Create Sales Order")
form_class = order_forms.EditSalesOrderForm
role_required = 'sales_order.add'
def get_initial(self):
initials = super().get_initial().copy()
@ -383,7 +372,6 @@ class PurchaseOrderEdit(AjaxUpdateView):
model = PurchaseOrder
ajax_form_title = _('Edit Purchase Order')
form_class = order_forms.EditPurchaseOrderForm
role_required = 'purchase_order.change'
def get_form(self):
@ -404,7 +392,6 @@ class SalesOrderEdit(AjaxUpdateView):
model = SalesOrder
ajax_form_title = _('Edit Sales Order')
form_class = order_forms.EditSalesOrderForm
role_required = 'sales_order.change'
def get_form(self):
form = super().get_form()
@ -422,7 +409,6 @@ class PurchaseOrderCancel(AjaxUpdateView):
ajax_form_title = _('Cancel Order')
ajax_template_name = 'order/order_cancel.html'
form_class = order_forms.CancelPurchaseOrderForm
role_required = 'purchase_order.change'
def validate(self, order, form, **kwargs):
@ -449,7 +435,6 @@ class SalesOrderCancel(AjaxUpdateView):
ajax_form_title = _("Cancel sales order")
ajax_template_name = "order/sales_order_cancel.html"
form_class = order_forms.CancelSalesOrderForm
role_required = 'sales_order.change'
def validate(self, order, form, **kwargs):
@ -476,7 +461,6 @@ class PurchaseOrderIssue(AjaxUpdateView):
ajax_form_title = _('Issue Order')
ajax_template_name = "order/order_issue.html"
form_class = order_forms.IssuePurchaseOrderForm
role_required = 'purchase_order.change'
def validate(self, order, form, **kwargs):
@ -506,7 +490,6 @@ class PurchaseOrderComplete(AjaxUpdateView):
ajax_template_name = "order/order_complete.html"
ajax_form_title = _("Complete Order")
context_object_name = 'order'
role_required = 'purchase_order.change'
def get_context_data(self):
@ -543,7 +526,6 @@ class SalesOrderShip(AjaxUpdateView):
context_object_name = 'order'
ajax_template_name = 'order/sales_order_ship.html'
ajax_form_title = _('Ship Order')
role_required = 'sales_order.change'
def post(self, request, *args, **kwargs):
@ -587,6 +569,8 @@ class PurchaseOrderExport(AjaxView):
"""
model = PurchaseOrder
# Specify role as we cannot introspect from "AjaxView"
role_required = 'purchase_order.view'
def get(self, request, *args, **kwargs):
@ -619,6 +603,8 @@ class PurchaseOrderReceive(AjaxUpdateView):
form_class = order_forms.ReceivePurchaseOrderForm
ajax_form_title = _("Receive Parts")
ajax_template_name = "order/receive_parts.html"
# Specify role as we do not specify a Model against this view
role_required = 'purchase_order.change'
# Where the parts will be going (selected in POST request)
@ -1117,7 +1103,6 @@ class POLineItemCreate(AjaxCreateView):
context_object_name = 'line'
form_class = order_forms.EditPurchaseOrderLineItemForm
ajax_form_title = _('Add Line Item')
role_required = 'purchase_order.add'
def validate(self, item, form, **kwargs):
@ -1201,7 +1186,6 @@ class SOLineItemCreate(AjaxCreateView):
context_order_name = 'line'
form_class = order_forms.EditSalesOrderLineItemForm
ajax_form_title = _('Add Line Item')
role_required = 'sales_order.add'
def get_form(self, *args, **kwargs):
@ -1253,7 +1237,6 @@ class SOLineItemEdit(AjaxUpdateView):
model = SalesOrderLineItem
form_class = order_forms.EditSalesOrderLineItemForm
ajax_form_title = _('Edit Line Item')
role_required = 'sales_order.change'
def get_form(self):
form = super().get_form()
@ -1272,7 +1255,6 @@ class POLineItemEdit(AjaxUpdateView):
form_class = order_forms.EditPurchaseOrderLineItemForm
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Line Item')
role_required = 'purchase_order.change'
def get_form(self):
form = super().get_form()
@ -1290,7 +1272,6 @@ class POLineItemDelete(AjaxDeleteView):
model = PurchaseOrderLineItem
ajax_form_title = _('Delete Line Item')
ajax_template_name = 'order/po_lineitem_delete.html'
role_required = 'purchase_order.delete'
def get_data(self):
return {
@ -1303,7 +1284,6 @@ class SOLineItemDelete(AjaxDeleteView):
model = SalesOrderLineItem
ajax_form_title = _("Delete Line Item")
ajax_template_name = "order/so_lineitem_delete.html"
role_required = 'sales_order.delete'
def get_data(self):
return {
@ -1317,7 +1297,6 @@ class SalesOrderAllocationCreate(AjaxCreateView):
model = SalesOrderAllocation
form_class = order_forms.EditSalesOrderAllocationForm
ajax_form_title = _('Allocate Stock to Order')
role_required = 'sales_order.add'
def get_initial(self):
initials = super().get_initial().copy()
@ -1392,7 +1371,6 @@ class SalesOrderAllocationEdit(AjaxUpdateView):
model = SalesOrderAllocation
form_class = order_forms.EditSalesOrderAllocationForm
ajax_form_title = _('Edit Allocation Quantity')
role_required = 'sales_order.change'
def get_form(self):
form = super().get_form()
@ -1410,4 +1388,3 @@ class SalesOrderAllocationDelete(AjaxDeleteView):
ajax_form_title = _("Remove allocation")
context_object_name = 'allocation'
ajax_template_name = "order/so_allocation_delete.html"
role_required = 'sales_order.delete'

View File

@ -57,8 +57,6 @@ class PartIndex(InvenTreeRoleMixin, ListView):
template_name = 'part/category.html'
context_object_name = 'parts'
role_required = 'part.view'
def get_queryset(self):
return Part.objects.all().select_related('category')
@ -85,7 +83,6 @@ class PartRelatedCreate(AjaxCreateView):
form_class = part_forms.CreatePartRelatedForm
ajax_form_title = _("Add Related Part")
ajax_template_name = "modal_form.html"
role_required = 'part.change'
def get_initial(self):
""" Set parent part as part_1 field """
@ -141,6 +138,8 @@ class PartRelatedDelete(AjaxDeleteView):
model = PartRelated
ajax_form_title = _("Delete Related Part")
context_object_name = "related"
# Explicit role requirement
role_required = 'part.change'
@ -154,8 +153,6 @@ class PartAttachmentCreate(AjaxCreateView):
ajax_form_title = _("Add part attachment")
ajax_template_name = "modal_form.html"
role_required = 'part.add'
def save(self, form, **kwargs):
"""
Record the user that uploaded this attachment
@ -208,8 +205,6 @@ class PartAttachmentEdit(AjaxUpdateView):
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit attachment')
role_required = 'part.change'
def get_data(self):
return {
'success': _('Part attachment updated')
@ -246,8 +241,6 @@ class PartTestTemplateCreate(AjaxCreateView):
form_class = part_forms.EditPartTestTemplateForm
ajax_form_title = _("Create Test Template")
role_required = 'part.add'
def get_initial(self):
initials = super().get_initial()
@ -275,8 +268,6 @@ class PartTestTemplateEdit(AjaxUpdateView):
form_class = part_forms.EditPartTestTemplateForm
ajax_form_title = _("Edit Test Template")
role_required = 'part.change'
def get_form(self):
form = super().get_form()
@ -291,8 +282,6 @@ class PartTestTemplateDelete(AjaxDeleteView):
model = PartTestTemplate
ajax_form_title = _("Delete Test Template")
role_required = 'part.delete'
class PartSetCategory(AjaxUpdateView):
""" View for settings the part category for multiple parts at once """
@ -386,8 +375,6 @@ class MakePartVariant(AjaxCreateView):
ajax_form_title = _('Create Variant')
ajax_template_name = 'part/variant_part.html'
role_required = 'part.add'
def get_part_template(self):
return get_object_or_404(Part, id=self.kwargs['pk'])
@ -468,8 +455,6 @@ class PartDuplicate(AjaxCreateView):
ajax_form_title = _("Duplicate Part")
ajax_template_name = "part/copy_part.html"
role_required = 'part.add'
def get_data(self):
return {
'success': _('Copied part')
@ -594,8 +579,6 @@ class PartCreate(AjaxCreateView):
ajax_form_title = _('Create New Part')
ajax_template_name = 'part/create_part.html'
role_required = 'part.add'
def get_data(self):
return {
'success': _("Created new part"),
@ -772,8 +755,6 @@ class PartDetail(InvenTreeRoleMixin, DetailView):
queryset = Part.objects.all().select_related('category')
template_name = 'part/detail.html'
role_required = 'part.view'
# Add in some extra context information based on query params
def get_context_data(self, **kwargs):
""" Provide extra context data to template
@ -859,8 +840,6 @@ class PartImageUpload(AjaxUpdateView):
form_class = part_forms.PartImageForm
role_required = 'part.change'
def get_data(self):
return {
'success': _('Updated part image'),
@ -874,8 +853,6 @@ class PartImageSelect(AjaxUpdateView):
ajax_template_name = 'part/select_image.html'
ajax_form_title = _('Select Part Image')
role_required = 'part.change'
fields = [
'image',
]
@ -917,8 +894,6 @@ class PartEdit(AjaxUpdateView):
ajax_form_title = _('Edit Part Properties')
context_object_name = 'part'
role_required = 'part.change'
def get_form(self):
""" Create form for Part editing.
Overrides default get_form() method to limit the choices
@ -948,7 +923,6 @@ class BomDuplicate(AjaxUpdateView):
ajax_form_title = _('Duplicate BOM')
ajax_template_name = 'part/bom_duplicate.html'
form_class = part_forms.BomDuplicateForm
role_required = 'part.change'
def get_form(self):
@ -1002,8 +976,6 @@ class BomValidate(AjaxUpdateView):
context_object_name = 'part'
form_class = part_forms.BomValidateForm
role_required = 'part.change'
def get_context(self):
return {
'part': self.get_object(),
@ -1854,8 +1826,6 @@ class PartDelete(AjaxDeleteView):
ajax_form_title = _('Confirm Part Deletion')
context_object_name = 'part'
role_required = 'part.delete'
success_url = '/part/'
def get_data(self):
@ -1977,9 +1947,9 @@ class PartPricing(AjaxView):
class PartParameterTemplateCreate(AjaxCreateView):
""" View for creating a new PartParameterTemplate """
role_required = 'part.add'
"""
View for creating a new PartParameterTemplate
"""
model = PartParameterTemplate
form_class = part_forms.EditPartParameterTemplateForm
@ -1987,9 +1957,9 @@ class PartParameterTemplateCreate(AjaxCreateView):
class PartParameterTemplateEdit(AjaxUpdateView):
""" View for editing a PartParameterTemplate """
role_required = 'part.change'
"""
View for editing a PartParameterTemplate
"""
model = PartParameterTemplate
form_class = part_forms.EditPartParameterTemplateForm
@ -1999,8 +1969,6 @@ class PartParameterTemplateEdit(AjaxUpdateView):
class PartParameterTemplateDelete(AjaxDeleteView):
""" View for deleting an existing PartParameterTemplate """
role_required = 'part.delete'
model = PartParameterTemplate
ajax_form_title = _("Delete Part Parameter Template")
@ -2008,8 +1976,6 @@ class PartParameterTemplateDelete(AjaxDeleteView):
class PartParameterCreate(AjaxCreateView):
""" View for creating a new PartParameter """
role_required = 'part.add'
model = PartParameter
form_class = part_forms.EditPartParameterForm
ajax_form_title = _('Create Part Parameter')
@ -2060,8 +2026,6 @@ class PartParameterCreate(AjaxCreateView):
class PartParameterEdit(AjaxUpdateView):
""" View for editing a PartParameter """
role_required = 'part.change'
model = PartParameter
form_class = part_forms.EditPartParameterForm
ajax_form_title = _('Edit Part Parameter')
@ -2076,8 +2040,6 @@ class PartParameterEdit(AjaxUpdateView):
class PartParameterDelete(AjaxDeleteView):
""" View for deleting a PartParameter """
role_required = 'part.change'
model = PartParameter
ajax_template_name = 'part/param_delete.html'
ajax_form_title = _('Delete Part Parameter')
@ -2091,8 +2053,6 @@ class CategoryDetail(InvenTreeRoleMixin, DetailView):
queryset = PartCategory.objects.all().prefetch_related('children')
template_name = 'part/category_partlist.html'
role_required = ['part_category.view', 'part.view']
def get_context_data(self, **kwargs):
context = super(CategoryDetail, self).get_context_data(**kwargs).copy()
@ -2135,14 +2095,15 @@ class CategoryParametric(CategoryDetail):
class CategoryEdit(AjaxUpdateView):
""" Update view to edit a PartCategory """
"""
Update view to edit a PartCategory
"""
model = PartCategory
form_class = part_forms.EditCategoryForm
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Part Category')
role_required = 'part_category.change'
def get_context_data(self, **kwargs):
context = super(CategoryEdit, self).get_context_data(**kwargs).copy()
@ -2173,15 +2134,16 @@ class CategoryEdit(AjaxUpdateView):
class CategoryDelete(AjaxDeleteView):
""" Delete view to delete a PartCategory """
"""
Delete view to delete a PartCategory
"""
model = PartCategory
ajax_template_name = 'part/category_delete.html'
ajax_form_title = _('Delete Part Category')
context_object_name = 'category'
success_url = '/part/'
role_required = 'part_category.delete'
def get_data(self):
return {
'danger': _('Part category was deleted'),
@ -2196,8 +2158,6 @@ class CategoryCreate(AjaxCreateView):
ajax_template_name = 'modal_form.html'
form_class = part_forms.EditCategoryForm
role_required = 'part_category.add'
def get_context_data(self, **kwargs):
""" Add extra context data to template.
@ -2236,8 +2196,6 @@ class CategoryCreate(AjaxCreateView):
class CategoryParameterTemplateCreate(AjaxCreateView):
""" View for creating a new PartCategoryParameterTemplate """
role_required = 'part_category.change'
model = PartCategoryParameterTemplate
form_class = part_forms.EditCategoryParameterTemplateForm
ajax_form_title = _('Create Category Parameter Template')
@ -2339,8 +2297,6 @@ class CategoryParameterTemplateCreate(AjaxCreateView):
class CategoryParameterTemplateEdit(AjaxUpdateView):
""" View for editing a PartCategoryParameterTemplate """
role_required = 'part_category.change'
model = PartCategoryParameterTemplate
form_class = part_forms.EditCategoryParameterTemplateForm
ajax_form_title = _('Edit Category Parameter Template')
@ -2398,8 +2354,6 @@ class CategoryParameterTemplateEdit(AjaxUpdateView):
class CategoryParameterTemplateDelete(AjaxDeleteView):
""" View for deleting an existing PartCategoryParameterTemplate """
role_required = 'part_category.change'
model = PartCategoryParameterTemplate
ajax_form_title = _("Delete Category Parameter Template")
@ -2413,14 +2367,15 @@ class CategoryParameterTemplateDelete(AjaxDeleteView):
class BomItemCreate(AjaxCreateView):
""" Create view for making a new BomItem object """
"""
Create view for making a new BomItem object
"""
model = BomItem
form_class = part_forms.EditBomItemForm
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Create BOM Item')
role_required = 'part.add'
def get_form(self):
""" Override get_form() method to reduce Part selection options.
@ -2491,8 +2446,6 @@ class BomItemEdit(AjaxUpdateView):
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit BOM item')
role_required = 'part.change'
def get_form(self):
""" Override get_form() method to filter part selection options
@ -2543,13 +2496,12 @@ class BomItemEdit(AjaxUpdateView):
class BomItemDelete(AjaxDeleteView):
""" Delete view for removing BomItem """
model = BomItem
ajax_template_name = 'part/bom-delete.html'
context_object_name = 'item'
ajax_form_title = _('Confim BOM item deletion')
role_required = 'part.change'
class PartSalePriceBreakCreate(AjaxCreateView):
""" View for creating a sale price break for a part """
@ -2558,8 +2510,6 @@ class PartSalePriceBreakCreate(AjaxCreateView):
form_class = part_forms.EditPartSalePriceBreakForm
ajax_form_title = _('Add Price Break')
role_required = 'part.add'
def get_data(self):
return {
'success': _('Added new price break')
@ -2608,8 +2558,6 @@ class PartSalePriceBreakEdit(AjaxUpdateView):
form_class = part_forms.EditPartSalePriceBreakForm
ajax_form_title = _('Edit Price Break')
role_required = 'part.change'
def get_form(self):
form = super().get_form()
@ -2624,5 +2572,3 @@ class PartSalePriceBreakDelete(AjaxDeleteView):
model = PartSellPriceBreak
ajax_form_title = _("Delete Price Break")
ajax_template_name = "modal_delete_form.html"
role_required = 'part.delete'

View File

@ -45,9 +45,6 @@ stock_tracking_urls = [
# delete
url(r'^(?P<pk>\d+)/delete', views.StockItemTrackingDelete.as_view(), name='stock-tracking-delete'),
# list
url('^.*$', views.StockTrackingIndex.as_view(), name='stock-tracking-list')
]
stock_urls = [

View File

@ -49,7 +49,6 @@ class StockIndex(InvenTreeRoleMixin, ListView):
model = StockItem
template_name = 'stock/location.html'
context_obect_name = 'locations'
role_required = 'stock.view'
def get_context_data(self, **kwargs):
context = super(StockIndex, self).get_context_data(**kwargs).copy()
@ -75,7 +74,6 @@ class StockLocationDetail(InvenTreeRoleMixin, DetailView):
template_name = 'stock/location.html'
queryset = StockLocation.objects.all()
model = StockLocation
role_required = ['stock_location.view', 'stock.view']
class StockItemDetail(InvenTreeRoleMixin, DetailView):
@ -87,7 +85,6 @@ class StockItemDetail(InvenTreeRoleMixin, DetailView):
template_name = 'stock/item.html'
queryset = StockItem.objects.all()
model = StockItem
role_required = 'stock.view'
class StockItemNotes(InvenTreeRoleMixin, UpdateView):
@ -96,6 +93,7 @@ class StockItemNotes(InvenTreeRoleMixin, UpdateView):
context_object_name = 'item'
template_name = 'stock/item_notes.html'
model = StockItem
role_required = 'stock.view'
fields = ['notes']
@ -123,7 +121,6 @@ class StockLocationEdit(AjaxUpdateView):
context_object_name = 'location'
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Stock Location')
role_required = 'stock_location.change'
def get_form(self):
""" Customize form data for StockLocation editing.
@ -246,6 +243,7 @@ class StockLocationQRCode(QRCodeView):
""" View for displaying a QR code for a StockLocation object """
ajax_form_title = _("Stock Location QR code")
role_required = ['stock_location.view', 'stock.view']
def get_qr_data(self):
@ -266,7 +264,6 @@ class StockItemAttachmentCreate(AjaxCreateView):
form_class = StockForms.EditStockItemAttachmentForm
ajax_form_title = _("Add Stock Item Attachment")
ajax_template_name = "modal_form.html"
role_required = 'stock.add'
def save(self, form, **kwargs):
""" Record the user that uploaded the attachment """
@ -312,7 +309,6 @@ class StockItemAttachmentEdit(AjaxUpdateView):
model = StockItemAttachment
form_class = StockForms.EditStockItemAttachmentForm
ajax_form_title = _("Edit Stock Item Attachment")
role_required = 'stock.change'
def get_form(self):
@ -331,7 +327,6 @@ class StockItemAttachmentDelete(AjaxDeleteView):
ajax_form_title = _("Delete Stock Item Attachment")
ajax_template_name = "attachment_delete.html"
context_object_name = "attachment"
role_required = 'stock.delete'
def get_data(self):
return {
@ -348,7 +343,6 @@ class StockItemAssignToCustomer(AjaxUpdateView):
ajax_form_title = _("Assign to Customer")
context_object_name = "item"
form_class = StockForms.AssignStockItemToCustomerForm
role_required = 'stock.change'
def validate(self, item, form, **kwargs):
@ -382,7 +376,6 @@ class StockItemReturnToStock(AjaxUpdateView):
ajax_form_title = _("Return to Stock")
context_object_name = "item"
form_class = StockForms.ReturnStockItemForm
role_required = 'stock.change'
def validate(self, item, form, **kwargs):
@ -412,6 +405,7 @@ class StockItemDeleteTestData(AjaxUpdateView):
model = StockItem
form_class = ConfirmForm
ajax_form_title = _("Delete All Test Data")
role_required = ['stock.change', 'stock.delete']
def get_form(self):
@ -448,7 +442,6 @@ class StockItemTestResultCreate(AjaxCreateView):
model = StockItemTestResult
form_class = StockForms.EditStockItemTestResultForm
ajax_form_title = _("Add Test Result")
role_required = 'stock.add'
def save(self, form, **kwargs):
"""
@ -489,7 +482,6 @@ class StockItemTestResultEdit(AjaxUpdateView):
model = StockItemTestResult
form_class = StockForms.EditStockItemTestResultForm
ajax_form_title = _("Edit Test Result")
role_required = 'stock.change'
def get_form(self):
@ -508,7 +500,6 @@ class StockItemTestResultDelete(AjaxDeleteView):
model = StockItemTestResult
ajax_form_title = _("Delete Test Result")
context_object_name = "result"
role_required = 'stock.delete'
class StockExportOptions(AjaxView):
@ -517,7 +508,6 @@ class StockExportOptions(AjaxView):
model = StockLocation
ajax_form_title = _('Stock Export Options')
form_class = StockForms.ExportOptionsForm
role_required = 'stock.view'
def post(self, request, *args, **kwargs):
@ -665,7 +655,6 @@ class StockItemInstall(AjaxUpdateView):
form_class = StockForms.InstallStockForm
ajax_form_title = _('Install Stock Item')
ajax_template_name = "stock/item_install.html"
role_required = 'stock.change'
part = None
@ -1232,7 +1221,6 @@ class StockItemEdit(AjaxUpdateView):
context_object_name = 'item'
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Edit Stock Item')
role_required = 'stock.change'
def get_form(self):
""" Get form for StockItem editing.
@ -1343,7 +1331,6 @@ class StockItemConvert(AjaxUpdateView):
ajax_form_title = _('Convert Stock Item')
ajax_template_name = 'stock/stockitem_convert.html'
context_object_name = 'item'
role_required = 'stock.change'
def get_form(self):
"""
@ -1369,7 +1356,6 @@ class StockLocationCreate(AjaxCreateView):
context_object_name = 'location'
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Create new Stock Location')
role_required = 'stock_location.add'
def get_initial(self):
initials = super(StockLocationCreate, self).get_initial().copy()
@ -1462,7 +1448,6 @@ class StockItemSerialize(AjaxUpdateView):
ajax_template_name = 'stock/item_serialize.html'
ajax_form_title = _('Serialize Stock')
form_class = StockForms.SerializeStockForm
role_required = 'stock.change'
def get_form(self):
@ -1555,7 +1540,6 @@ class StockItemCreate(AjaxCreateView):
context_object_name = 'item'
ajax_template_name = 'modal_form.html'
ajax_form_title = _('Create new Stock Item')
role_required = 'stock.add'
def get_part(self, form=None):
"""
@ -1880,7 +1864,6 @@ class StockLocationDelete(AjaxDeleteView):
ajax_template_name = 'stock/location_delete.html'
context_object_name = 'location'
ajax_form_title = _('Delete Stock Location')
role_required = 'stock_location.delete'
class StockItemDelete(AjaxDeleteView):
@ -1894,7 +1877,6 @@ class StockItemDelete(AjaxDeleteView):
ajax_template_name = 'stock/item_delete.html'
context_object_name = 'item'
ajax_form_title = _('Delete Stock Item')
role_required = 'stock.delete'
class StockItemTrackingDelete(AjaxDeleteView):
@ -1906,18 +1888,6 @@ class StockItemTrackingDelete(AjaxDeleteView):
model = StockItemTracking
ajax_template_name = 'stock/tracking_delete.html'
ajax_form_title = _('Delete Stock Tracking Entry')
role_required = 'stock.delete'
class StockTrackingIndex(InvenTreeRoleMixin, ListView):
"""
StockTrackingIndex provides a page to display StockItemTracking objects
"""
model = StockItemTracking
template_name = 'stock/tracking.html'
context_object_name = 'items'
role_required = 'stock.view'
class StockItemTrackingEdit(AjaxUpdateView):
@ -1926,7 +1896,6 @@ class StockItemTrackingEdit(AjaxUpdateView):
model = StockItemTracking
ajax_form_title = _('Edit Stock Tracking Entry')
form_class = StockForms.TrackingEntryForm
role_required = 'stock.change'
class StockItemTrackingCreate(AjaxCreateView):
@ -1936,7 +1905,6 @@ class StockItemTrackingCreate(AjaxCreateView):
model = StockItemTracking
ajax_form_title = _("Add Stock Tracking Entry")
form_class = StockForms.TrackingEntryForm
role_required = 'stock.add'
def post(self, request, *args, **kwargs):

View File

@ -68,6 +68,7 @@ class RuleSet(models.Model):
'part_partparameter',
'part_partrelated',
'part_partstar',
'company_supplierpart',
],
'stock_location': [
'stock_stocklocation',
@ -94,11 +95,11 @@ class RuleSet(models.Model):
],
'purchase_order': [
'company_company',
'company_supplierpart',
'company_supplierpricebreak',
'order_purchaseorder',
'order_purchaseorderattachment',
'order_purchaseorderlineitem',
'company_supplierpart',
],
'sales_order': [
'company_company',
@ -342,7 +343,7 @@ def update_group_roles(group, debug=False):
content_type = ContentType.objects.get(app_label=app, model=model)
permission = Permission.objects.get(content_type=content_type, codename=perm)
except ContentType.DoesNotExist:
print(f"Error: Could not find permission matching '{permission_string}'")
raise ValueError(f"Error: Could not find permission matching '{permission_string}'")
permission = None
return permission