Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2021-02-05 16:19:17 +11:00
commit ff5846732c
6 changed files with 113 additions and 4 deletions

View File

@ -1,3 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.test import TestCase from django.test import TestCase
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError

View File

@ -8,7 +8,7 @@ from .models import ReportSnippet, TestReport, ReportAsset
class ReportTemplateAdmin(admin.ModelAdmin): class ReportTemplateAdmin(admin.ModelAdmin):
list_display = ('name', 'description', 'template', 'filters', 'enabled') list_display = ('name', 'description', 'template', 'filters', 'enabled', 'revision')
class ReportSnippetAdmin(admin.ModelAdmin): class ReportSnippetAdmin(admin.ModelAdmin):

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.7 on 2021-02-05 00:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('report', '0008_auto_20210204_2100'),
]
operations = [
migrations.AddField(
model_name='testreport',
name='revision',
field=models.PositiveIntegerField(default=1, help_text='Report revision number (auto-increments)', verbose_name='Revision'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.7 on 2021-02-05 01:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('report', '0009_testreport_revision'),
]
operations = [
migrations.AlterField(
model_name='testreport',
name='revision',
field=models.PositiveIntegerField(default=1, editable=False, help_text='Report revision number (auto-increments)', verbose_name='Revision'),
),
]

View File

@ -7,12 +7,14 @@ from __future__ import unicode_literals
import os import os
import sys import sys
import logging
import datetime import datetime
from django.db import models from django.db import models
from django.conf import settings from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.core.validators import FileExtensionValidator from django.core.validators import FileExtensionValidator
import stock.models import stock.models
@ -29,6 +31,35 @@ except OSError as err:
sys.exit(1) sys.exit(1)
logger = logging.getLogger(__name__)
class ReportFileUpload(FileSystemStorage):
"""
Custom implementation of FileSystemStorage class.
When uploading a report (or a snippet / asset / etc),
it is often important to ensure the filename is not arbitrarily *changed*,
if the name of the uploaded file is identical to the currently stored file.
For example, a snippet or asset file is referenced in a template by filename,
and we do not want that filename to change when we upload a new *version*
of the snippet or asset file.
This uploader class performs the following pseudo-code function:
- If the model is *new*, proceed as normal
- If the model is being updated:
a) If the new filename is *different* from the existing filename, proceed as normal
b) If the new filename is *identical* to the existing filename, we want to overwrite the existing file
"""
def get_available_name(self, name, max_length=None):
print("Name:", name)
return super().get_available_name(name, max_length)
def rename_template(instance, filename): def rename_template(instance, filename):
return instance.rename_file(filename) return instance.rename_file(filename)
@ -62,6 +93,13 @@ class ReportBase(models.Model):
class Meta: class Meta:
abstract = True abstract = True
def save(self, *args, **kwargs):
# Increment revision number
self.revision += 1
super().save()
def __str__(self): def __str__(self):
return "{n} - {d}".format(n=self.name, d=self.description) return "{n} - {d}".format(n=self.name, d=self.description)
@ -113,6 +151,13 @@ class ReportBase(models.Model):
help_text=_("Report template description") help_text=_("Report template description")
) )
revision = models.PositiveIntegerField(
default=1,
verbose_name=_("Revision"),
help_text=_("Report revision number (auto-increments)"),
editable=False,
)
class ReportTemplateBase(ReportBase): class ReportTemplateBase(ReportBase):
""" """
@ -145,6 +190,7 @@ class ReportTemplateBase(ReportBase):
context['report_name'] = self.name context['report_name'] = self.name
context['report_description'] = self.description context['report_description'] = self.description
context['report_revision'] = self.revision
context['request'] = request context['request'] = request
context['user'] = request.user context['user'] = request.user
context['date'] = datetime.datetime.now().date() context['date'] = datetime.datetime.now().date()
@ -220,7 +266,19 @@ def rename_snippet(instance, filename):
filename = os.path.basename(filename) filename = os.path.basename(filename)
return os.path.join('report', 'snippets', filename) path = os.path.join('report', 'snippets', filename)
# If the snippet file is the *same* filename as the one being uploaded,
# delete the original one from the media directory
if str(filename) == str(instance.snippet):
fullpath = os.path.join(settings.MEDIA_ROOT, path)
fullpath = os.path.abspath(fullpath)
if os.path.exists(fullpath):
logger.info(f"Deleting existing snippet file: '{filename}'")
os.remove(fullpath)
return path
class ReportSnippet(models.Model): class ReportSnippet(models.Model):
@ -244,7 +302,19 @@ def rename_asset(instance, filename):
filename = os.path.basename(filename) filename = os.path.basename(filename)
return os.path.join('report', 'assets', filename) path = os.path.join('report', 'assets', filename)
# If the asset file is the *same* filename as the one being uploaded,
# delete the original one from the media directory
if str(filename) == str(instance.asset):
fullpath = os.path.join(settings.MEDIA_ROOT, path)
fullpath = os.path.abspath(fullpath)
if os.path.exists(fullpath):
logger.info(f"Deleting existing asset file: '{filename}'")
os.remove(fullpath)
return path
class ReportAsset(models.Model): class ReportAsset(models.Model):

View File

@ -52,7 +52,7 @@ function selectTestReport(reports, items, options={}) {
<form method='post' action='' class='js-modal-form' enctype='multipart/form-data'> <form method='post' action='' class='js-modal-form' enctype='multipart/form-data'>
<div class='form-group'> <div class='form-group'>
<label class='control-label requiredField' for='id_report'> <label class='control-label requiredField' for='id_report'>
{% trans "Select Label" %} {% trans "Select Report Template" %}
</label> </label>
<div class='controls'> <div class='controls'>
<select id='id_report' class='select form-control name='report'> <select id='id_report' class='select form-control name='report'>