18 changes: 9 additions & 9 deletions InvenTree/part/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
import import_export.widgets as widgets
from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field
from import_export.resources import ModelResource

import part.models as models
from company.models import SupplierPart
from InvenTree.admin import InvenTreeResource
from stock.models import StockLocation


class PartResource(ModelResource):
""" Class for managing Part data import/export """
class PartResource(InvenTreeResource):
"""Class for managing Part data import/export."""

# ForeignKey fields
category = Field(attribute='category', widget=widgets.ForeignKeyWidget(models.PartCategory))
Expand Down Expand Up @@ -81,8 +81,8 @@ class PartAdmin(ImportExportModelAdmin):
]


class PartCategoryResource(ModelResource):
""" Class for managing PartCategory data import/export """
class PartCategoryResource(InvenTreeResource):
"""Class for managing PartCategory data import/export."""

parent = Field(attribute='parent', widget=widgets.ForeignKeyWidget(models.PartCategory))

Expand Down Expand Up @@ -157,8 +157,8 @@ class PartTestTemplateAdmin(admin.ModelAdmin):
autocomplete_fields = ('part',)


class BomItemResource(ModelResource):
""" Class for managing BomItem data import/export """
class BomItemResource(InvenTreeResource):
"""Class for managing BomItem data import/export."""

level = Field(attribute='level', readonly=True)

Expand Down Expand Up @@ -269,8 +269,8 @@ class ParameterTemplateAdmin(ImportExportModelAdmin):
search_fields = ('name', 'units')


class ParameterResource(ModelResource):
""" Class for managing PartParameter data import/export """
class ParameterResource(InvenTreeResource):
"""Class for managing PartParameter data import/export."""

part = Field(attribute='part', widget=widgets.ForeignKeyWidget(models.Part))

Expand Down
10 changes: 5 additions & 5 deletions InvenTree/stock/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
import import_export.widgets as widgets
from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field
from import_export.resources import ModelResource

from build.models import Build
from company.models import Company, SupplierPart
from InvenTree.admin import InvenTreeResource
from order.models import PurchaseOrder, SalesOrder
from part.models import Part

from .models import (StockItem, StockItemAttachment, StockItemTestResult,
StockItemTracking, StockLocation)


class LocationResource(ModelResource):
""" Class for managing StockLocation data import/export """
class LocationResource(InvenTreeResource):
"""Class for managing StockLocation data import/export."""

parent = Field(attribute='parent', widget=widgets.ForeignKeyWidget(StockLocation))

Expand Down Expand Up @@ -65,8 +65,8 @@ class LocationAdmin(ImportExportModelAdmin):
]


class StockItemResource(ModelResource):
""" Class for managing StockItem data import/export """
class StockItemResource(InvenTreeResource):
"""Class for managing StockItem data import/export."""

# Custom managers for ForeignKey fields
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
Expand Down
2 changes: 1 addition & 1 deletion InvenTree/templates/js/translated/attachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ function loadAttachmentTable(url, options) {

var html = `<span class='fas ${icon}'></span> ${filename}`;

return renderLink(html, value);
return renderLink(html, value, {download: true});
} else if (row.link) {
var html = `<span class='fas fa-link'></span> ${row.link}`;
return renderLink(html, row.link);
Expand Down
3 changes: 3 additions & 0 deletions InvenTree/templates/js/translated/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ function constructChangeForm(fields, options) {
},
success: function(data) {

// Ensure the data are fully sanitized before we operate on it
data = sanitizeData(data);

// An optional function can be provided to process the returned results,
// before they are rendered to the form
if (options.processResults) {
Expand Down
3 changes: 2 additions & 1 deletion InvenTree/templates/js/translated/stock.js
Original file line number Diff line number Diff line change
Expand Up @@ -1306,7 +1306,8 @@ function loadStockTestResultsTable(table, options) {
var html = value;

if (row.attachment) {
html += `<a href='${row.attachment}'><span class='fas fa-file-alt float-right'></span></a>`;
var text = `<span class='fas fa-file-alt float-right'></span>`;
html += renderLink(text, row.attachment, {download: true});
}

return html;
Expand Down
54 changes: 53 additions & 1 deletion InvenTree/templates/js/translated/tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ function renderLink(text, url, options={}) {

var max_length = options.max_length || -1;

var extra = '';

if (options.download) {
var fn = url.split('/').at(-1);
extra += ` download='${fn}'`;
}

// Shorten the displayed length if required
if ((max_length > 0) && (text.length > max_length)) {
var slice_length = (max_length - 3) / 2;
Expand All @@ -102,7 +109,7 @@ function renderLink(text, url, options={}) {
text = `${text_start}...${text_end}`;
}

return '<a href="' + url + '">' + text + '</a>';
return `<a href='${url}'${extra}>${text}</a>`;
}


Expand Down Expand Up @@ -282,6 +289,8 @@ $.fn.inventreeTable = function(options) {
// Extract query params
var filters = options.queryParams || options.filters || {};

options.escape = true;

// Store the total set of query params
options.query_params = filters;

Expand Down Expand Up @@ -468,6 +477,49 @@ function customGroupSorter(sortName, sortOrder, sortData) {

$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['en-US-custom']);

// Enable HTML escaping by default
$.fn.bootstrapTable.escape = true;

// Override the 'calculateObjectValue' function at bootstrap-table.js:3525
// Allows us to escape any nasty HTML tags which are rendered to the DOM
$.fn.bootstrapTable.utils._calculateObjectValue = $.fn.bootstrapTable.utils.calculateObjectValue;

$.fn.bootstrapTable.utils.calculateObjectValue = function escapeCellValue(self, name, args, defaultValue) {

var args_list = [];

if (args) {

args_list.push(args[0]);

if (name && typeof(name) === 'function' && name.name == 'formatter') {
/* This is a custom "formatter" function for a particular cell,
* which may side-step regular HTML escaping, and inject malicious code into the DOM.
*
* Here we have access to the 'args' supplied to the custom 'formatter' function,
* which are in the order:
* args = [value, row, index, field]
*
* 'row' is the one we are interested in
*/

var row = Object.assign({}, args[1]);

args_list.push(sanitizeData(row));
} else {
args_list.push(args[1]);
}

for (var ii = 2; ii < args.length; ii++) {
args_list.push(args[ii]);
}
}

var value = $.fn.bootstrapTable.utils._calculateObjectValue(self, name, args_list, defaultValue);

return value;
};

})(jQuery);

$.extend($.fn.treegrid.defaults, {
Expand Down