From b5e993872feefe52ca6f3fc7cf43d672ac0cd1b9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 5 Feb 2021 13:51:25 +1100 Subject: [PATCH] Keep asset and snippet filenames the same (if possible) --- InvenTree/report/models.py | 59 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index b10e2db32b..0c77f4d19a 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -7,12 +7,14 @@ from __future__ import unicode_literals import os import sys +import logging import datetime from django.db import models from django.conf import settings +from django.core.files.storage import FileSystemStorage from django.core.validators import FileExtensionValidator import stock.models @@ -29,6 +31,35 @@ except OSError as err: 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): return instance.rename_file(filename) @@ -235,7 +266,19 @@ def rename_snippet(instance, 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): @@ -259,7 +302,19 @@ def rename_asset(instance, 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):