diff options
author | Philip Sargent <philip.sargent@gmail.com> | 2025-02-11 19:28:20 +0000 |
---|---|---|
committer | Philip Sargent <philip.sargent@gmail.com> | 2025-02-11 19:28:20 +0000 |
commit | d05b6b9b5fe8987a681ab80f408c66636731c31c (patch) | |
tree | 2760a4a618a4c752892731a5a35332c9240a71b9 | |
parent | 096c3be4e51c121af9486d6c9a2667d029d20f12 (diff) | |
download | troggle-d05b6b9b5fe8987a681ab80f408c66636731c31c.tar.gz troggle-d05b6b9b5fe8987a681ab80f408c66636731c31c.tar.bz2 troggle-d05b6b9b5fe8987a681ab80f408c66636731c31c.zip |
fix many glitches for unusual JPGs
-rw-r--r-- | core/utils.py | 34 | ||||
-rw-r--r-- | core/views/editor_helpers.py | 53 |
2 files changed, 58 insertions, 29 deletions
diff --git a/core/utils.py b/core/utils.py index 3129ffe..5e03971 100644 --- a/core/utils.py +++ b/core/utils.py @@ -97,10 +97,19 @@ def chaosmonkey(n): def unique_slug(text, n): """This gives an almost-unique id based on the text, 2 hex digits would seem adequate, but we might get a collision. - Not used anywhere. + Deterministic """ sha.update(text.encode('utf-8')) return sha.hexdigest()[0:n] + +def random_slug(text, n): + """This gives an almost-unique id based on the text, + 2 hex digits would seem adequate, but we might get a collision. + Random + """ + text = text + alphabet_suffix(3) + sha.update(text.encode('utf-8')) + return sha.hexdigest()[0:n] def alphabet_suffix(n): """This is called repeatedly during initial parsing import, hence the cached list @@ -230,10 +239,10 @@ def get_cookie(request): so having a blank is best. """ # NO_COOKIE_DEFAULT = 'Unset Cookie <hohlenforscher@potatohut.expo>' - print(f"-- Getting cookie...") + # print(f"-- Getting cookie...") editor_id = request.COOKIES.get('editor_id', "") # if no cookie, then default string "" editor = git_string(editor_id) # belt and braces, should have been validity checked on saving already - print(f"-- Cookie to be used: {editor=}") + # print(f"-- Cookie to be used: {editor=}") return editor def git_string(author_string): @@ -248,7 +257,7 @@ def git_string(author_string): return "" if author_regex.match(author_string): - print(f"++ Is valid git-compatible author string: '{author_string}'") + # print(f"++ Is valid git-compatible author string: '{author_string}'") return author_string else: editor = author_string.replace("@","_at_") @@ -267,7 +276,7 @@ def git_add(filename, cwd, commands=[]): # what is the purpose of this 'git diff' ? To prevent merge conflicts happening I guess, # so we do not have to reverse a 'git add' - print(f"git diff {filename} in {cwd}") + # print(f"git diff {filename} in {cwd}") cmd_diff = [git, "diff", filename] commands.append(cmd_diff) cp_diff = subprocess.run(cmd_diff, cwd=cwd, capture_output=True, text=True) @@ -349,11 +358,9 @@ def add_commit(fname, message, editor): def write_binary_file(filepath, content): print(f"write_binary_file: {filepath}") - write_files([(filepath, content, "")]) - -def write_files(files): - for filepath, content, encoding in files: - filename = filepath.name + write_files([(filepath, content, "")]) # null encoding does "wb" + +def ensure_dir_exists(filepath): if filepath.is_dir(): raise OSError( f"CANNOT write this file {filepath} as this is an existing DIRECTORY." @@ -369,6 +376,11 @@ def write_files(files): raise OSError( f"CANNOT make the directory for {filepath}. Ask a nerd to fix this: {e}" ) + +def write_files(files): + for filepath, content, encoding in files: + filename = filepath.name + ensure_dir_exists(filepath) if encoding: mode = "w" kwargs = {"encoding": encoding} @@ -377,7 +389,7 @@ def write_files(files): kwargs = {} try: with open(filepath, mode, **kwargs) as f: - print(f"WRITING {filepath} ") + # print(f"WRITING {filepath} ") f.write(content) except PermissionError as e: raise PermissionError( diff --git a/core/views/editor_helpers.py b/core/views/editor_helpers.py index 11d8e3a..1a3ad2f 100644 --- a/core/views/editor_helpers.py +++ b/core/views/editor_helpers.py @@ -16,7 +16,10 @@ from django.conf import settings as django_settings from PIL import Image import troggle.settings as settings -from troggle.core.utils import COOKIE_MAX_AGE, WriteAndCommitError, get_cookie, git_string, write_binary_file, write_and_commit, current_expo +from troggle.core.utils import ( COOKIE_MAX_AGE, + WriteAndCommitError, get_cookie, git_string, write_binary_file, + write_and_commit, current_expo, random_slug, ensure_dir_exists + ) from .auth import login_required_if_public @@ -120,11 +123,11 @@ def new_image_form(request, path): THUMB_QUALITY = 70 IMAGE_QUALITY = 85 directory = get_dir(path) - print(f"new_image_form(): {directory=} {path=}") + # print(f"new_image_form(): {directory=} {path=}") editor = get_cookie(request) - print(f"{django_settings.FILE_UPLOAD_MAX_MEMORY_SIZE=}") - FILE_UPLOAD_MAX_MEMORY_SIZE = 0 # force uploaded files to be temporary in /tmp, not in-memory + # print(f"{django_settings.FILE_UPLOAD_MAX_MEMORY_SIZE=}") + # FILE_UPLOAD_MAX_MEMORY_SIZE = 0 # force uploaded files to be temporary in /tmp, not in-memory if request.method == "POST": # print(f"new_image_form(): POST ") form = NewWebImageForm(request.POST, request.FILES, directory=directory) @@ -156,11 +159,11 @@ def new_image_form(request, path): # int(f"new_image_form() After DUMP {exif=}") except: exif = None - if not descrip: - # date and time from exif data - descrip = f"{exif_dict['Exif'][36867].decode()} {exif_dict['Exif'][36880].decode()}" - if not year: - year = exif_dict['Exif'][36867].decode()[:4] + # date and time from exif data + if 36867 in exif_dict['Exif'] and 36880 in exif_dict['Exif']: + descrip += f"\n\n{exif_dict['Exif'][36867].decode()} {exif_dict['Exif'][36880].decode()}" + if not year: + year = exif_dict['Exif'][36867].decode()[:4] else: year = current_expo() # replace with year from photo exif if possible exif = None @@ -169,13 +172,13 @@ def new_image_form(request, path): # print(f"new_image_form(): {i.size=}") if width > MAX_IMAGE_WIDTH or height > MAX_IMAGE_HEIGHT: scale = max(width / MAX_IMAGE_WIDTH, height / MAX_IMAGE_HEIGHT) - print(f"new_image_form(): rescaling {scale=}") + # print(f"new_image_form(): rescaling {scale=}") try: i = i.resize((int(width / scale), int(height / scale)), Image.LANCZOS) except Exception as e: print(f"new_image_form(): rescaling exception: {e} ") - print(f"new_image_form(): rescaled ") + # print(f"new_image_form(): rescaled ") tscale = max(width / THUMBNAIL_WIDTH, height / THUMBNAIL_HEIGHT) t = i.resize((int(width / tscale), int(height / tscale)), Image.LANCZOS) t = t.convert('RGB') @@ -197,7 +200,7 @@ def new_image_form(request, path): t.save(tb, format='JPEG', quality = THUMB_QUALITY) image_rel_path, thumb_rel_path, desc_rel_path = form.get_rel_paths() - print(f"new_image_form(): \n {image_rel_path=}\n {thumb_rel_path=}\n {desc_rel_path=}") + # print(f"new_image_form(): \n {image_rel_path=}\n {thumb_rel_path=}\n {desc_rel_path=}") image_page_template = loader.get_template("image_page_template.html") image_page = image_page_template.render( { @@ -211,7 +214,7 @@ def new_image_form(request, path): image_path, thumb_path, desc_path = form.get_full_paths() # Create directories if required for full_path in image_path, thumb_path, desc_path: - print(full_path, full_path.parent) + # print(full_path, full_path.parent) full_path.parent.mkdir(parents=True, exist_ok=True) try: change_message = form.cleaned_data["change_message"] @@ -264,7 +267,7 @@ def save_original_in_expofiles(f, year, photographer): will catch photos uploaded directly from phones which otherwise never get recorded properly in original format. - Django does small files in memory, which is a pain. + Django does small files <2.5 MB in memory, which is a pain. """ if photographer: photographer = photographer.strip().replace(" ","") @@ -272,15 +275,29 @@ def save_original_in_expofiles(f, year, photographer): photographer = "Anonymous" directory = settings.EXPOFILES / "photos" / year / photographer / "expoweb_originals" filepath = (directory / f.name) + ensure_dir_exists(filepath) if isinstance(f, InMemoryUploadedFile): - print("In-memory file content:", f,f.content_type, f.size, f.charset, f.content_type_extra, f.read()) + # print("In-memory file content:", f,f.content_type, f.size, f.charset, f.content_type_extra, f.read()) + f.open() # rewind to beginning content = f.read() - print(f"In-memory file content: content read: {len(content)}") - # THIS DOES NOT WORK, which is why we force all uploads to use a temporary file not in-memory write_binary_file(filepath, content) elif isinstance(f, TemporaryUploadedFile): - dest = shutil.move(f.temporary_file_path(), filepath) + if filepath.is_file: + print(f"+++++ Out of cheese error\n Destination EXISTS {filepath}") + tail = random_slug(str(filepath), 2) + newname = f"{filepath.stem}_{tail}{filepath.suffix}" + filepath = filepath.parent / newname + print(f"+++++ The turtle moves\n Attempting to use {filepath}") + if Path(f.temporary_file_path()).is_file: + # print(f"+++++ Found {f.temporary_file_path()}") + try: + dest = shutil.move(f.temporary_file_path(), filepath) + except Exception as e: + print("+++++ ",e) + raise + else: + print(f"+++++ Out of cheese error\n Can't find {f.temporary_file_path()}") else: msg = f"Unknown uploaded file type: {f}, should be a temporary file or in-memory." print(msg) |