From 05484f61480a30596563877c2f6b09a51bd57136 Mon Sep 17 00:00:00 2001 From: Gregoo Date: Fri, 17 Jan 2025 18:08:15 +0100 Subject: [PATCH] Refactor nil image code, and add a built-in fix for missing nil images --- bricktracker/minifigure.py | 19 +---------- bricktracker/part.py | 18 +---------- bricktracker/rebrickable_image.py | 22 ++++++++++++- bricktracker/set.py | 25 +++----------- bricktracker/views/admin.py | 54 ++++++++++++++++++++++++++++++- templates/admin.html | 3 ++ templates/admin/image.html | 14 ++++++++ 7 files changed, 98 insertions(+), 57 deletions(-) create mode 100644 templates/admin/image.html diff --git a/bricktracker/minifigure.py b/bricktracker/minifigure.py index 98375e3..7a7adf6 100644 --- a/bricktracker/minifigure.py +++ b/bricktracker/minifigure.py @@ -1,4 +1,3 @@ -import os from sqlite3 import Row from typing import Any, Self, TYPE_CHECKING @@ -126,23 +125,7 @@ class BrickMinifigure(BrickRecord): else: file = self.fields.fig_num - folder: str = current_app.config['MINIFIGURES_FOLDER'].value - - # /!\ Everything is saved as .jpg, even if it came from a .png - # not changing this behaviour. - - # Grab the extension - # _, extension = os.path.splitext(self.part_img_url) - extension = '.jpg' - - # Compute the path - path = os.path.join(folder, '{number}{ext}'.format( - number=file, - ext=extension, - )) - - return url_for('static', filename=path) - + return RebrickableImage.static_url(file, 'MINIFIGURES_FOLDER') else: if self.fields.set_img_url is None: return current_app.config['REBRICKABLE_IMAGE_NIL_MINIFIGURE'].value # noqa: E501 diff --git a/bricktracker/part.py b/bricktracker/part.py index a401579..e14b6c0 100644 --- a/bricktracker/part.py +++ b/bricktracker/part.py @@ -208,23 +208,7 @@ class BrickPart(BrickRecord): else: file = self.fields.part_img_url_id - folder: str = current_app.config['PARTS_FOLDER'].value - - # /!\ Everything is saved as .jpg, even if it came from a .png - # not changing this behaviour. - - # Grab the extension - # _, extension = os.path.splitext(self.part_img_url) - extension = '.jpg' - - # Compute the path - path = os.path.join(folder, '{number}{ext}'.format( - number=file, - ext=extension, - )) - - return url_for('static', filename=path) - + return RebrickableImage.static_url(file, 'PARTS_FOLDER') else: if self.fields.part_img_url is None: return current_app.config['REBRICKABLE_IMAGE_NIL'].value diff --git a/bricktracker/rebrickable_image.py b/bricktracker/rebrickable_image.py index fa52100..513e4b2 100644 --- a/bricktracker/rebrickable_image.py +++ b/bricktracker/rebrickable_image.py @@ -2,7 +2,7 @@ import os from typing import TYPE_CHECKING from urllib.parse import urlparse -from flask import current_app +from flask import current_app, url_for import requests from shutil import copyfileobj @@ -138,3 +138,23 @@ class RebrickableImage(object): ) return filename + + # Return the static URL for an image given a name and folder + @staticmethod + def static_url(name: str, folder_name: str) -> str: + folder: str = current_app.config[folder_name].value + + # /!\ Everything is saved as .jpg, even if it came from a .png + # not changing this behaviour. + + # Grab the extension + # _, extension = os.path.splitext(self.part_img_url) + extension = '.jpg' + + # Compute the path + path = os.path.join(folder, '{name}{ext}'.format( + name=name, + ext=extension, + )) + + return url_for('static', filename=path) diff --git a/bricktracker/set.py b/bricktracker/set.py index 77c9d47..2f1778e 100644 --- a/bricktracker/set.py +++ b/bricktracker/set.py @@ -1,4 +1,3 @@ -import os from sqlite3 import Row from typing import Any, Self @@ -9,6 +8,7 @@ from .instructions import BrickInstructions from .instructions_list import BrickInstructionsList from .minifigure_list import BrickMinifigureList from .part_list import BrickPartList +from .rebrickable_image import RebrickableImage from .record import BrickRecord from .sql import BrickSQL from .theme_list import BrickThemeList @@ -158,25 +158,10 @@ class BrickSet(BrickRecord): # Compute the url for the set image def url_for_image(self, /) -> str: if not current_app.config['USE_REMOTE_IMAGES'].value: - folder: str = current_app.config['SETS_FOLDER'].value - - # /!\ Everything is saved as .jpg, even if it came from a .png - # not changing this behaviour. - - # Grab the extension - # _, extension = os.path.splitext(self.fields.img_url) - extension = '.jpg' - # Grab the extension - _, extension = os.path.splitext(self.fields.set_img_url) - - # Compute the path - path = os.path.join(folder, '{number}{ext}'.format( - number=self.fields.set_num, - ext=extension, - )) - - return url_for('static', filename=path) - + return RebrickableImage.static_url( + self.fields.set_num, + 'SETS_FOLDER' + ) else: return self.fields.set_img_url diff --git a/bricktracker/views/admin.py b/bricktracker/views/admin.py index 2a5addf..77b8c63 100644 --- a/bricktracker/views/admin.py +++ b/bricktracker/views/admin.py @@ -18,7 +18,11 @@ from werkzeug.wrappers.response import Response from ..configuration_list import BrickConfigurationList from .exceptions import exception_handler from ..instructions_list import BrickInstructionsList +from ..minifigure import BrickMinifigure +from ..part import BrickPart +from ..rebrickable_image import RebrickableImage from ..retired_list import BrickRetiredList +from ..set import BrickSet from ..sql import BrickSQL from ..theme_list import BrickThemeList from .upload import upload_helper @@ -34,9 +38,13 @@ admin_page = Blueprint('admin', __name__, url_prefix='/admin') @exception_handler(__file__) def admin() -> str: counters: dict[str, int] = {} + count_none: int = 0 exception: Exception | None = None is_init: bool = False - count_none: int = 0 + nil_minifigure_name: str = '' + nil_minifigure_url: str = '' + nil_part_name: str = '' + nil_part_url: str = '' # This view needs to be protected against SQL errors try: @@ -49,6 +57,18 @@ def admin() -> str: if record is not None: count_none = record['count'] + nil_minifigure_name = RebrickableImage.nil_minifigure_name() + nil_minifigure_url = RebrickableImage.static_url( + nil_minifigure_name, + 'MINIFIGURES_FOLDER' + ) + + nil_part_name = RebrickableImage.nil_name() + nil_part_url = RebrickableImage.static_url( + nil_part_name, + 'PARTS_FOLDER' + ) + except Exception as e: exception = e @@ -57,12 +77,14 @@ def admin() -> str: exception=str(e), )) + open_image = request.args.get('open_image', None) open_instructions = request.args.get('open_instructions', None) open_logout = request.args.get('open_logout', None) open_retired = request.args.get('open_retired', None) open_theme = request.args.get('open_theme', None) open_database = ( + open_image is None and open_instructions is None and open_logout is None and open_retired is None and @@ -78,7 +100,12 @@ def admin() -> str: exception=exception, instructions=BrickInstructionsList(), is_init=is_init, + nil_minifigure_name=nil_minifigure_name, + nil_minifigure_url=nil_minifigure_url, + nil_part_name=nil_part_name, + nil_part_url=nil_part_url, open_database=open_database, + open_image=open_image, open_instructions=open_instructions, open_logout=open_logout, open_retired=open_retired, @@ -241,6 +268,31 @@ def refresh_themes() -> Response: return redirect(url_for('admin.admin', open_theme=True)) +# Update the default images +@admin_page.route('/update-image', methods=['GET']) +@login_required +@exception_handler(__file__) +def update_image() -> Response: + # Abusing the object to create a 'nil' minifigure + RebrickableImage( + BrickSet(), + minifigure=BrickMinifigure(record={ + 'set_img_url': None, + }) + ).download() + + # Abusing the object to create a 'nil' part + RebrickableImage( + BrickSet(), + part=BrickPart(record={ + 'part_img_url': None, + 'part_img_url_id': None + }) + ).download() + + return redirect(url_for('admin.admin', open_image=True)) + + # Update the themes file @admin_page.route('/update-retired', methods=['GET']) @login_required diff --git a/templates/admin.html b/templates/admin.html index 0f4df0d..9e172bc 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -21,6 +21,9 @@ {% else %} {% include 'admin/logout.html' %} {% include 'admin/instructions.html' %} + {% if not config['USE_REMOTE_IMAGES'].value %} + {% include 'admin/image.html' %} + {% endif %} {% include 'admin/theme.html' %} {% include 'admin/retired.html' %} {% include 'admin/database.html' %} diff --git a/templates/admin/image.html b/templates/admin/image.html new file mode 100644 index 0000000..4741fc9 --- /dev/null +++ b/templates/admin/image.html @@ -0,0 +1,14 @@ +{% import 'macro/accordion.html' as accordion %} + +{{ accordion.header('Default images', 'image', 'admin', expanded=open_image, icon='image-line') }} +

+ If you do not see the following image, you either do not need them or you are coming from the original version of BrickTracker and or they have been moved.. +

+
+ {{ nil_minifigure_name }} + {{ nil_part_name }} +
+

+ Update the images +

+{{ accordion.footer() }}