Skip to content

Commit

Permalink
Fix API endpoint permission for the "AttachmentMixin" class (#3218)
Browse files Browse the repository at this point in the history
* Fix API endpoint permission for the "AttachmentMixin" class

- Any authenticated user could perform CREATE and UPDATE operations on attachments
- Could be performed via the browsable DRF API
- Could also be performed via the front-end (with some advaned jiggering of OPTIONS code)

* Show or hide buttons depending on the permissions of the user

* Add shortcut for table permission check
  • Loading branch information
SchrodingersGat committed Jun 18, 2022
1 parent 18cf92e commit 12fcccb
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 46 deletions.
6 changes: 5 additions & 1 deletion InvenTree/InvenTree/api.py
Expand Up @@ -11,6 +11,7 @@
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,
Expand Down Expand Up @@ -182,7 +183,10 @@ def download_queryset(self, queryset, export_format):
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,
Expand Down
2 changes: 1 addition & 1 deletion InvenTree/templates/attachment_table.html
Expand Up @@ -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>
Expand Down
133 changes: 89 additions & 44 deletions InvenTree/templates/js/translated/attachment.js
Expand Up @@ -136,19 +136,56 @@ function loadAttachmentTable(url, options) {

var table = options.table || '#attachment-table';

setupFilterList('attachments', $(table), '#filter-list-attachments');

addAttachmentButtonCallbacks(url, options.fields || {});
var permissions = {};

// Add callback for the 'multi delete' button
$('#multi-attachment-delete').click(function() {
var attachments = getTableData(table);
// 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;
}

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',
Expand All @@ -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');

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" %}',
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" %}',
});
});
});
}

// 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: [
{
Expand Down Expand Up @@ -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" %}',
);

html += makeIconButton(
'fa-trash-alt icon-red',
'button-attachment-delete',
row.pk,
'{% trans "Delete attachment" %}',
);
if (permissions.change) {
html += makeIconButton(
'fa-edit icon-blue',
'button-attachment-edit',
row.pk,
'{% trans "Edit attachment" %}',
);
}

if (permissions.delete) {
html += makeIconButton(
'fa-trash-alt icon-red',
'button-attachment-delete',
row.pk,
'{% trans "Delete attachment" %}',
);
}

html += `</div>`;

Expand Down
5 changes: 5 additions & 0 deletions InvenTree/users/models.py
Expand Up @@ -222,6 +222,11 @@ class Meta:
@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
Expand Down

0 comments on commit 12fcccb

Please sign in to comment.