mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
b31fd6227b
@ -11,6 +11,7 @@ from rest_framework.response import Response
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from InvenTree.mixins import ListCreateAPI
|
||||
from InvenTree.permissions import RolePermission
|
||||
|
||||
from .status import is_worker_running
|
||||
from .version import (inventreeApiVersion, inventreeInstanceName,
|
||||
@ -182,7 +183,10 @@ class APIDownloadMixin:
|
||||
class AttachmentMixin:
|
||||
"""Mixin for creating attachment objects, and ensuring the user information is saved correctly."""
|
||||
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
permission_classes = [
|
||||
permissions.IsAuthenticated,
|
||||
RolePermission,
|
||||
]
|
||||
|
||||
filter_backends = [
|
||||
DjangoFilterBackend,
|
||||
|
@ -841,12 +841,13 @@ for app in SOCIAL_BACKENDS:
|
||||
|
||||
SOCIALACCOUNT_PROVIDERS = CONFIG.get('social_providers', [])
|
||||
|
||||
SOCIALACCOUNT_STORE_TOKENS = True
|
||||
|
||||
# settings for allauth
|
||||
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = get_setting('INVENTREE_LOGIN_CONFIRM_DAYS', CONFIG.get('login_confirm_days', 3))
|
||||
|
||||
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = get_setting('INVENTREE_LOGIN_ATTEMPTS', CONFIG.get('login_attempts', 5))
|
||||
|
||||
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
|
||||
ACCOUNT_PREVENT_ENUMERATION = True
|
||||
|
||||
# override forms / adapters
|
||||
ACCOUNT_FORMS = {
|
||||
|
@ -172,7 +172,7 @@
|
||||
<h4>{% trans "Allocate Stock to Build" %}</h4>
|
||||
{% include "spacer.html" %}
|
||||
<div class='btn-group' role='group'>
|
||||
{% if build.active and build.has_untracked_bom_items %}
|
||||
{% if roles.build.add and build.active and build.has_untracked_bom_items %}
|
||||
<button class='btn btn-danger' type='button' id='btn-unallocate' title='{% trans "Unallocate stock" %}'>
|
||||
<span class='fas fa-minus-circle'></span> {% trans "Unallocate Stock" %}
|
||||
</button>
|
||||
@ -229,7 +229,7 @@
|
||||
<h4>{% trans "Incomplete Build Outputs" %}</h4>
|
||||
{% include "spacer.html" %}
|
||||
<div class='btn-group' role='group'>
|
||||
{% if build.active %}
|
||||
{% if roles.build.add and build.active %}
|
||||
<button class='btn btn-success' type='button' id='btn-create-output' title='{% trans "Create new build output" %}'>
|
||||
<span class='fas fa-plus-circle'></span> {% trans "New Build Output" %}
|
||||
</button>
|
||||
@ -249,12 +249,16 @@
|
||||
<span class='fas fa-tools'></span> <span class='caret'></span>
|
||||
</button>
|
||||
<ul class='dropdown-menu'>
|
||||
{% if roles.build.add %}
|
||||
<li><a class='dropdown-item' href='#' id='multi-output-complete' title='{% trans "Complete selected build outputs" %}'>
|
||||
<span class='fas fa-check-circle icon-green'></span> {% trans "Complete outputs" %}
|
||||
</a></li>
|
||||
{% endif %}
|
||||
{% if roles.build.delete %}
|
||||
<li><a class='dropdown-item' href='#' id='multi-output-delete' title='{% trans "Delete selected build outputs" %}'>
|
||||
<span class='fas fa-trash-alt icon-red'></span> {% trans "Delete outputs" %}
|
||||
</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -20,9 +20,11 @@
|
||||
<h4>{% trans "Part Stock" %}</h4>
|
||||
{% include "spacer.html" %}
|
||||
<div class='btn-group' role='group'>
|
||||
{% if roles.stock.add %}
|
||||
<button type='button' class='btn btn-success' id='new-stock-item' title='{% trans "Create new stock item" %}'>
|
||||
<span class='fas fa-plus-circle'></span> {% trans "New Stock Item" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -147,9 +147,11 @@
|
||||
<h4>{% trans "Installed Stock Items" %}</h4>
|
||||
{% include "spacer.html" %}
|
||||
<div class='btn-group' role='group'>
|
||||
{% if roles.stock.add %}
|
||||
<button type='button' class='btn btn-success' id='stock-item-install'>
|
||||
<span class='fas fa-plus-circle'></span> {% trans "Install Stock Item" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<div id='attachment-buttons'>
|
||||
<div class='btn-group' role='group'>
|
||||
<div class='btn-group'>
|
||||
<div class='btn-group' id='multi-attachment-actions'>
|
||||
<button class='btn btn-primary dropdown-toggle' type='button' data-bs-toggle='dropdown' title='{% trans "Actions" %}'>
|
||||
<span class='fas fa-tools'></span> <span class='caret'></span>
|
||||
</button>
|
||||
|
@ -136,19 +136,56 @@ function loadAttachmentTable(url, options) {
|
||||
|
||||
var table = options.table || '#attachment-table';
|
||||
|
||||
setupFilterList('attachments', $(table), '#filter-list-attachments');
|
||||
var permissions = {};
|
||||
|
||||
addAttachmentButtonCallbacks(url, options.fields || {});
|
||||
// First we determine which permissions the user has for this attachment table
|
||||
$.ajax({
|
||||
url: url,
|
||||
async: false,
|
||||
type: 'OPTIONS',
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
accepts: {
|
||||
json: 'application/json',
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.actions.DELETE) {
|
||||
permissions.delete = true;
|
||||
}
|
||||
|
||||
// Add callback for the 'multi delete' button
|
||||
$('#multi-attachment-delete').click(function() {
|
||||
var attachments = getTableData(table);
|
||||
|
||||
if (attachments.length > 0) {
|
||||
deleteAttachments(attachments, url, options);
|
||||
if (response.actions.POST) {
|
||||
permissions.change = true;
|
||||
permissions.add = true;
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
showApiError(xhr, url);
|
||||
}
|
||||
});
|
||||
|
||||
setupFilterList('attachments', $(table), '#filter-list-attachments');
|
||||
|
||||
if (permissions.add) {
|
||||
addAttachmentButtonCallbacks(url, options.fields || {});
|
||||
} else {
|
||||
// Hide the buttons
|
||||
$('#new-attachment').hide();
|
||||
$('#new-attachment-link').hide();
|
||||
}
|
||||
|
||||
if (permissions.delete) {
|
||||
// Add callback for the 'multi delete' button
|
||||
$('#multi-attachment-delete').click(function() {
|
||||
var attachments = getTableData(table);
|
||||
|
||||
if (attachments.length > 0) {
|
||||
deleteAttachments(attachments, url, options);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$('#multi-attachment-actions').hide();
|
||||
}
|
||||
|
||||
$(table).inventreeTable({
|
||||
url: url,
|
||||
name: options.name || 'attachments',
|
||||
@ -162,32 +199,36 @@ function loadAttachmentTable(url, options) {
|
||||
onPostBody: function() {
|
||||
|
||||
// Add callback for 'edit' button
|
||||
$(table).find('.button-attachment-edit').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
if (permissions.change) {
|
||||
$(table).find('.button-attachment-edit').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
constructForm(`${url}${pk}/`, {
|
||||
fields: {
|
||||
link: {},
|
||||
comment: {},
|
||||
},
|
||||
processResults: function(data, fields, opts) {
|
||||
// Remove the "link" field if the attachment is a file!
|
||||
if (data.attachment) {
|
||||
delete opts.fields.link;
|
||||
}
|
||||
},
|
||||
onSuccess: reloadAttachmentTable,
|
||||
title: '{% trans "Edit Attachment" %}',
|
||||
constructForm(`${url}${pk}/`, {
|
||||
fields: {
|
||||
link: {},
|
||||
comment: {},
|
||||
},
|
||||
processResults: function(data, fields, opts) {
|
||||
// Remove the "link" field if the attachment is a file!
|
||||
if (data.attachment) {
|
||||
delete opts.fields.link;
|
||||
}
|
||||
},
|
||||
onSuccess: reloadAttachmentTable,
|
||||
title: '{% trans "Edit Attachment" %}',
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Add callback for 'delete' button
|
||||
$(table).find('.button-attachment-delete').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
if (permissions.delete) {
|
||||
// Add callback for 'delete' button
|
||||
$(table).find('.button-attachment-delete').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
var attachment = $(table).bootstrapTable('getRowByUniqueId', pk);
|
||||
deleteAttachments([attachment], url, options);
|
||||
});
|
||||
var attachment = $(table).bootstrapTable('getRowByUniqueId', pk);
|
||||
deleteAttachments([attachment], url, options);
|
||||
});
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
@ -261,19 +302,23 @@ function loadAttachmentTable(url, options) {
|
||||
|
||||
html = `<div class='btn-group float-right' role='group'>`;
|
||||
|
||||
html += makeIconButton(
|
||||
'fa-edit icon-blue',
|
||||
'button-attachment-edit',
|
||||
row.pk,
|
||||
'{% trans "Edit attachment" %}',
|
||||
);
|
||||
if (permissions.change) {
|
||||
html += makeIconButton(
|
||||
'fa-edit icon-blue',
|
||||
'button-attachment-edit',
|
||||
row.pk,
|
||||
'{% trans "Edit attachment" %}',
|
||||
);
|
||||
}
|
||||
|
||||
html += makeIconButton(
|
||||
'fa-trash-alt icon-red',
|
||||
'button-attachment-delete',
|
||||
row.pk,
|
||||
'{% trans "Delete attachment" %}',
|
||||
);
|
||||
if (permissions.delete) {
|
||||
html += makeIconButton(
|
||||
'fa-trash-alt icon-red',
|
||||
'button-attachment-delete',
|
||||
row.pk,
|
||||
'{% trans "Delete attachment" %}',
|
||||
);
|
||||
}
|
||||
|
||||
html += `</div>`;
|
||||
|
||||
|
@ -222,6 +222,11 @@ class RuleSet(models.Model):
|
||||
@classmethod
|
||||
def check_table_permission(cls, user, table, permission):
|
||||
"""Check if the provided user has the specified permission against the table."""
|
||||
|
||||
# Superuser knows no bounds
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
# If the table does *not* require permissions
|
||||
if table in cls.RULESET_IGNORE:
|
||||
return True
|
||||
|
@ -7,7 +7,7 @@ coverage==5.3 # Unit test coverage
|
||||
coveralls==2.1.2 # Coveralls linking (for Travis)
|
||||
cryptography==3.4.8 # Cryptography support
|
||||
django-admin-shell==0.1.2 # Python shell for the admin interface
|
||||
django-allauth==0.45.0 # SSO for external providers via OpenID
|
||||
django-allauth==0.48.0 # SSO for external providers via OpenID
|
||||
django-allauth-2fa==0.9 # MFA / 2FA
|
||||
django-cleanup==5.1.0 # Manage deletion of old / unused uploaded files
|
||||
django-cors-headers==3.2.0 # CORS headers extension for DRF
|
||||
|
Loading…
Reference in New Issue
Block a user