diff --git a/bricktracker/app.py b/bricktracker/app.py index a55a9f7..f6054bc 100644 --- a/bricktracker/app.py +++ b/bricktracker/app.py @@ -13,7 +13,7 @@ from bricktracker.sql import close from bricktracker.version import __version__ from bricktracker.views.add import add_page from bricktracker.views.admin.admin import admin_page -from bricktracker.views.admin.checkbox import admin_checkbox_page +from bricktracker.views.admin.status import admin_status_page from bricktracker.views.admin.database import admin_database_page from bricktracker.views.admin.image import admin_image_page from bricktracker.views.admin.instructions import admin_instructions_page @@ -78,7 +78,7 @@ def setup_app(app: Flask) -> None: # Register admin routes app.register_blueprint(admin_page) - app.register_blueprint(admin_checkbox_page) + app.register_blueprint(admin_status_page) app.register_blueprint(admin_database_page) app.register_blueprint(admin_image_page) app.register_blueprint(admin_instructions_page) diff --git a/bricktracker/metadata.py b/bricktracker/metadata.py index df93c93..e21bfdd 100644 --- a/bricktracker/metadata.py +++ b/bricktracker/metadata.py @@ -93,7 +93,7 @@ class BrickMetadata(BrickRecord): metadata_id=self.fields.id ) - # Select a specific checkbox (with an id) + # Select a specific metadata (with an id) def select_specific(self, id: str, /) -> Self: # Save the parameters to the fields self.fields.id = id diff --git a/bricktracker/migrations/0007.py b/bricktracker/migrations/0007.py index 9b0f589..81e4535 100644 --- a/bricktracker/migrations/0007.py +++ b/bricktracker/migrations/0007.py @@ -7,7 +7,7 @@ if TYPE_CHECKING: # Grab the list of checkboxes to create a list of SQL columns def migration_0007(sql: 'BrickSQL', /) -> dict[str, Any]: # Don't realy on sql files as they could be removed in the future - sql.cursor.execute('SELECT "bricktracker_set_checkboxes"."id" FROM "bricktracker_set_checkboxes') # noqa: E501 + sql.cursor.execute('SELECT "bricktracker_set_checkboxes"."id" FROM "bricktracker_set_checkboxes"') # noqa: E501 records = sql.cursor.fetchall() return { diff --git a/bricktracker/record_list.py b/bricktracker/record_list.py index 0798991..2275203 100644 --- a/bricktracker/record_list.py +++ b/bricktracker/record_list.py @@ -8,13 +8,13 @@ if TYPE_CHECKING: from .part import BrickPart from .rebrickable_set import RebrickableSet from .set import BrickSet - from .set_checkbox import BrickSetCheckbox + from .set_status import BrickSetStatus from .wish import BrickWish T = TypeVar( 'T', 'BrickSet', - 'BrickSetCheckbox', + 'BrickSetStatus', 'BrickPart', 'BrickMinifigure', 'BrickWish', diff --git a/bricktracker/reload.py b/bricktracker/reload.py index 62564df..28de7bf 100644 --- a/bricktracker/reload.py +++ b/bricktracker/reload.py @@ -1,6 +1,6 @@ from .instructions_list import BrickInstructionsList from .retired_list import BrickRetiredList -from .set_checkbox_list import BrickSetCheckboxList +from .set_status_list import BrickSetStatusList from .theme_list import BrickThemeList @@ -11,8 +11,8 @@ def reload() -> None: # Reload the instructions BrickInstructionsList(force=True) - # Reload the checkboxes - BrickSetCheckboxList(force=True) + # Reload the set statuses + BrickSetStatusList(force=True) # Reload retired sets BrickRetiredList(force=True) diff --git a/bricktracker/set.py b/bricktracker/set.py index 6b2da47..1b11a94 100644 --- a/bricktracker/set.py +++ b/bricktracker/set.py @@ -9,7 +9,7 @@ from .exceptions import NotFoundException from .minifigure_list import BrickMinifigureList from .part_list import BrickPartList from .rebrickable_set import RebrickableSet -from .set_checkbox_list import BrickSetCheckboxList +from .set_status_list import BrickSetStatusList from .sql import BrickSQL if TYPE_CHECKING: from .socket import BrickSocket @@ -161,7 +161,7 @@ class BrickSet(RebrickableSet): # Load from database if not self.select( - statuses=BrickSetCheckboxList().as_columns(solo=True) + statuses=BrickSetStatusList().as_columns(solo=True) ): raise NotFoundException( 'Set with ID {id} was not found in the database'.format( diff --git a/bricktracker/set_list.py b/bricktracker/set_list.py index 349af66..47d31b2 100644 --- a/bricktracker/set_list.py +++ b/bricktracker/set_list.py @@ -3,7 +3,7 @@ from typing import Self from flask import current_app from .record_list import BrickRecordList -from .set_checkbox_list import BrickSetCheckboxList +from .set_status_list import BrickSetStatusList from .set import BrickSet @@ -37,7 +37,7 @@ class BrickSetList(BrickRecordList[BrickSet]): # Load the sets from the database for record in self.select( order=self.order, - statuses=BrickSetCheckboxList().as_columns() + statuses=BrickSetStatusList().as_columns() ): brickset = BrickSet(record=record) @@ -73,7 +73,7 @@ class BrickSetList(BrickRecordList[BrickSet]): for record in self.select( order=order, limit=limit, - statuses=BrickSetCheckboxList().as_columns() + statuses=BrickSetStatusList().as_columns() ): brickset = BrickSet(record=record) diff --git a/bricktracker/set_checkbox.py b/bricktracker/set_status.py similarity index 60% rename from bricktracker/set_checkbox.py rename to bricktracker/set_status.py index f38b5f6..3b874f5 100644 --- a/bricktracker/set_checkbox.py +++ b/bricktracker/set_status.py @@ -4,20 +4,20 @@ from .exceptions import ErrorException from .metadata import BrickMetadata -# Lego set checkbox -class BrickSetCheckbox(BrickMetadata): - kind: str = 'checkbox' +# Lego set status metadata +class BrickSetStatus(BrickMetadata): + kind: str = 'status' prefix: str = 'status' # Set state endpoint set_state_endpoint: str = 'set.update_status' # Queries - delete_query: str = 'checkbox/delete' - insert_query: str = 'checkbox/insert' - select_query: str = 'checkbox/select' - update_field_query: str = 'checkbox/update/field' - update_set_state_query: str = 'set/update/status' + delete_query: str = 'set/metadata/status/delete' + insert_query: str = 'set/metadata/status/insert' + select_query: str = 'set/metadata/status/select' + update_field_query: str = 'set/metadata/status/update/field' + update_set_state_query: str = 'set/metadata/status/update/state' # Grab data from a form def from_form(self, form: dict[str, str], /) -> Self: @@ -25,7 +25,7 @@ class BrickSetCheckbox(BrickMetadata): grid = form.get('grid', None) if name is None or name == '': - raise ErrorException('Checkbox name cannot be empty') + raise ErrorException('Status name cannot be empty') self.fields.name = name self.fields.displayed_on_grid = grid == 'on' diff --git a/bricktracker/set_checkbox_list.py b/bricktracker/set_status_list.py similarity index 51% rename from bricktracker/set_checkbox_list.py rename to bricktracker/set_status_list.py index 6564e8d..12ce85a 100644 --- a/bricktracker/set_checkbox_list.py +++ b/bricktracker/set_status_list.py @@ -3,39 +3,39 @@ import logging from .exceptions import NotFoundException from .fields import BrickRecordFields from .record_list import BrickRecordList -from .set_checkbox import BrickSetCheckbox +from .set_status import BrickSetStatus logger = logging.getLogger(__name__) -# Lego sets checkbox list -class BrickSetCheckboxList(BrickRecordList[BrickSetCheckbox]): - checkboxes: dict[str, BrickSetCheckbox] +# Lego sets status list +class BrickSetStatusList(BrickRecordList[BrickSetStatus]): + statuses: dict[str, BrickSetStatus] # Queries - select_query = 'checkbox/list' + select_query = 'set/metadata/status/list' def __init__(self, /, *, force: bool = False): - # Load checkboxes only if there is none already loaded + # Load statuses only if there is none already loaded records = getattr(self, 'records', None) if records is None or force: # Don't use super()__init__ as it would mask class variables self.fields = BrickRecordFields() - logger.info('Loading set checkboxes list') + logger.info('Loading set statuses list') - BrickSetCheckboxList.records = [] - BrickSetCheckboxList.checkboxes = {} + BrickSetStatusList.records = [] + BrickSetStatusList.statuses = {} - # Load the checkboxes from the database + # Load the statuses from the database for record in self.select(): - checkbox = BrickSetCheckbox(record=record) + status = BrickSetStatus(record=record) - BrickSetCheckboxList.records.append(checkbox) - BrickSetCheckboxList.checkboxes[checkbox.fields.id] = checkbox + BrickSetStatusList.records.append(status) + BrickSetStatusList.statuses[status.fields.id] = status - # Return the checkboxes as columns for a select + # Return the statuses as columns for a select def as_columns( self, /, @@ -53,19 +53,19 @@ class BrickSetCheckboxList(BrickRecordList[BrickSetCheckbox]): if solo or record.fields.displayed_on_grid ]) - # Grab a specific checkbox - def get(self, id: str, /) -> BrickSetCheckbox: - if id not in self.checkboxes: + # Grab a specific status + def get(self, id: str, /) -> BrickSetStatus: + if id not in self.statuses: raise NotFoundException( - 'Checkbox with ID {id} was not found in the database'.format( + 'Status with ID {id} was not found in the database'.format( id=id, ), ) - return self.checkboxes[id] + return self.statuses[id] - # Get the list of checkboxes depending on the context - def list(self, /, *, all: bool = False) -> list[BrickSetCheckbox]: + # Get the list of statuses depending on the context + def list(self, /, *, all: bool = False) -> list[BrickSetStatus]: return [ record for record diff --git a/bricktracker/sql.py b/bricktracker/sql.py index 9e47d9a..18f7e99 100644 --- a/bricktracker/sql.py +++ b/bricktracker/sql.py @@ -318,13 +318,18 @@ class BrickSQL(object): ), package='bricktracker' ) + except Exception: + module = None + # If a module has been loaded, we need to fail if an error + # occured while executing the migration function + if module is not None: function = getattr(module, 'migration_{name}'.format( name=pending.name )) context: dict[str, Any] = function(self) - except Exception: + else: context: dict[str, Any] = {} self.executescript(pending.get_query(), **context) diff --git a/bricktracker/sql/checkbox/base.sql b/bricktracker/sql/checkbox/base.sql deleted file mode 100644 index 9726a6c..0000000 --- a/bricktracker/sql/checkbox/base.sql +++ /dev/null @@ -1,7 +0,0 @@ -SELECT - "bricktracker_set_checkboxes"."id", - "bricktracker_set_checkboxes"."name", - "bricktracker_set_checkboxes"."displayed_on_grid" -FROM "bricktracker_set_checkboxes" - -{% block where %}{% endblock %} \ No newline at end of file diff --git a/bricktracker/sql/checkbox/delete.sql b/bricktracker/sql/checkbox/delete.sql deleted file mode 100644 index 6eae9d0..0000000 --- a/bricktracker/sql/checkbox/delete.sql +++ /dev/null @@ -1,9 +0,0 @@ -BEGIN TRANSACTION; - -ALTER TABLE "bricktracker_set_statuses" -DROP COLUMN "status_{{ id }}"; - -DELETE FROM "bricktracker_set_checkboxes" -WHERE "bricktracker_set_checkboxes"."id" IS NOT DISTINCT FROM '{{ id }}'; - -COMMIT; \ No newline at end of file diff --git a/bricktracker/sql/checkbox/list.sql b/bricktracker/sql/checkbox/list.sql deleted file mode 100644 index 7420eb3..0000000 --- a/bricktracker/sql/checkbox/list.sql +++ /dev/null @@ -1 +0,0 @@ -{% extends 'checkbox/base.sql' %} diff --git a/bricktracker/sql/checkbox/select.sql b/bricktracker/sql/checkbox/select.sql deleted file mode 100644 index 76557a8..0000000 --- a/bricktracker/sql/checkbox/select.sql +++ /dev/null @@ -1,5 +0,0 @@ -{% extends 'checkbox/base.sql' %} - -{% block where %} -WHERE "bricktracker_set_checkboxes"."id" IS NOT DISTINCT FROM :id -{% endblock %} \ No newline at end of file diff --git a/bricktracker/sql/checkbox/update/field.sql b/bricktracker/sql/checkbox/update/field.sql deleted file mode 100644 index a65e3c0..0000000 --- a/bricktracker/sql/checkbox/update/field.sql +++ /dev/null @@ -1,3 +0,0 @@ -UPDATE "bricktracker_set_checkboxes" -SET "{{field}}" = :value -WHERE "bricktracker_set_checkboxes"."id" IS NOT DISTINCT FROM :id diff --git a/bricktracker/sql/migrations/0012.sql b/bricktracker/sql/migrations/0012.sql new file mode 100644 index 0000000..d656e29 --- /dev/null +++ b/bricktracker/sql/migrations/0012.sql @@ -0,0 +1,7 @@ +-- description: Rename checkboxes to status metadata + +BEGIN TRANSACTION; + +ALTER TABLE "bricktracker_set_checkboxes" RENAME TO "bricktracker_metadata_statuses"; + +COMMIT; \ No newline at end of file diff --git a/bricktracker/sql/schema/drop.sql b/bricktracker/sql/schema/drop.sql index 78ea32c..abc8522 100644 --- a/bricktracker/sql/schema/drop.sql +++ b/bricktracker/sql/schema/drop.sql @@ -1,5 +1,6 @@ BEGIN transaction; +DROP TABLE IF EXISTS "bricktracker_metadata_statuses"; DROP TABLE IF EXISTS "bricktracker_minifigures"; DROP TABLE IF EXISTS "bricktracker_parts"; DROP TABLE IF EXISTS "bricktracker_sets"; diff --git a/bricktracker/sql/set/metadata/status/base.sql b/bricktracker/sql/set/metadata/status/base.sql new file mode 100644 index 0000000..b1b2167 --- /dev/null +++ b/bricktracker/sql/set/metadata/status/base.sql @@ -0,0 +1,7 @@ +SELECT + "bricktracker_metadata_statuses"."id", + "bricktracker_metadata_statuses"."name", + "bricktracker_metadata_statuses"."displayed_on_grid" +FROM "bricktracker_metadata_statuses" + +{% block where %}{% endblock %} \ No newline at end of file diff --git a/bricktracker/sql/set/metadata/status/delete.sql b/bricktracker/sql/set/metadata/status/delete.sql new file mode 100644 index 0000000..cac284e --- /dev/null +++ b/bricktracker/sql/set/metadata/status/delete.sql @@ -0,0 +1,9 @@ +BEGIN TRANSACTION; + +ALTER TABLE "bricktracker_set_statuses" +DROP COLUMN "status_{{ id }}"; + +DELETE FROM "bricktracker_metadata_statuses" +WHERE "bricktracker_metadata_statuses"."id" IS NOT DISTINCT FROM '{{ id }}'; + +COMMIT; \ No newline at end of file diff --git a/bricktracker/sql/checkbox/insert.sql b/bricktracker/sql/set/metadata/status/insert.sql similarity index 84% rename from bricktracker/sql/checkbox/insert.sql rename to bricktracker/sql/set/metadata/status/insert.sql index 5de9c17..2704d72 100644 --- a/bricktracker/sql/checkbox/insert.sql +++ b/bricktracker/sql/set/metadata/status/insert.sql @@ -3,7 +3,7 @@ BEGIN TRANSACTION; ALTER TABLE "bricktracker_set_statuses" ADD COLUMN "status_{{ id }}" BOOLEAN NOT NULL DEFAULT 0; -INSERT INTO "bricktracker_set_checkboxes" ( +INSERT INTO "bricktracker_metadata_statuses" ( "id", "name", "displayed_on_grid" diff --git a/bricktracker/sql/set/metadata/status/list.sql b/bricktracker/sql/set/metadata/status/list.sql new file mode 100644 index 0000000..2fe9994 --- /dev/null +++ b/bricktracker/sql/set/metadata/status/list.sql @@ -0,0 +1 @@ +{% extends 'set/metadata/status/base.sql' %} diff --git a/bricktracker/sql/set/metadata/status/select.sql b/bricktracker/sql/set/metadata/status/select.sql new file mode 100644 index 0000000..09afe87 --- /dev/null +++ b/bricktracker/sql/set/metadata/status/select.sql @@ -0,0 +1,5 @@ +{% extends 'set/metadata/status/base.sql' %} + +{% block where %} +WHERE "bricktracker_metadata_statuses"."id" IS NOT DISTINCT FROM :id +{% endblock %} \ No newline at end of file diff --git a/bricktracker/sql/set/metadata/status/update/field.sql b/bricktracker/sql/set/metadata/status/update/field.sql new file mode 100644 index 0000000..d17681e --- /dev/null +++ b/bricktracker/sql/set/metadata/status/update/field.sql @@ -0,0 +1,3 @@ +UPDATE "bricktracker_metadata_statuses" +SET "{{field}}" = :value +WHERE "bricktracker_metadata_statuses"."id" IS NOT DISTINCT FROM :id diff --git a/bricktracker/sql/set/update/status.sql b/bricktracker/sql/set/metadata/status/update/state.sql similarity index 100% rename from bricktracker/sql/set/update/status.sql rename to bricktracker/sql/set/metadata/status/update/state.sql diff --git a/bricktracker/sql_counter.py b/bricktracker/sql_counter.py index 2e5c072..28c03a3 100644 --- a/bricktracker/sql_counter.py +++ b/bricktracker/sql_counter.py @@ -2,11 +2,12 @@ from typing import Tuple # Some table aliases to make it look cleaner (id: (name, icon)) ALIASES: dict[str, Tuple[str, str]] = { + 'bricktracker_metadata_statuses': ('Bricktracker set status metadata', 'checkbox-line'), # noqa: E501 'bricktracker_minifigures': ('Bricktracker minifigures', 'group-line'), 'bricktracker_parts': ('Bricktracker parts', 'shapes-line'), - 'bricktracker_set_checkboxes': ('Bricktracker set checkboxes', 'checkbox-line'), # noqa: E501 - 'bricktracker_set_statuses': ('Bricktracker sets status', 'checkbox-circle-line'), # noqa: E501 - 'bricktracker_set_storages': ('Bricktracker sets storages', 'archive-2-line'), # noqa: E501 + 'bricktracker_set_checkboxes': ('Bricktracker set checkboxes (legacy)', 'checkbox-line'), # noqa: E501 + 'bricktracker_set_statuses': ('Bricktracker set statuses', 'checkbox-line'), # noqa: E501 + 'bricktracker_set_storages': ('Bricktracker set storages', 'archive-2-line'), # noqa: E501 'bricktracker_sets': ('Bricktracker sets', 'hashtag'), 'bricktracker_wishes': ('Bricktracker wishes', 'gift-line'), 'inventory': ('Parts', 'shapes-line'), diff --git a/bricktracker/version.py b/bricktracker/version.py index 172ecf1..11dd9c9 100644 --- a/bricktracker/version.py +++ b/bricktracker/version.py @@ -1,4 +1,4 @@ from typing import Final __version__: Final[str] = '1.2.0' -__database_version__: Final[int] = 11 +__database_version__: Final[int] = 12 diff --git a/bricktracker/views/admin/admin.py b/bricktracker/views/admin/admin.py index d5586ea..a7f8ce7 100644 --- a/bricktracker/views/admin/admin.py +++ b/bricktracker/views/admin/admin.py @@ -8,8 +8,8 @@ from ..exceptions import exception_handler from ...instructions_list import BrickInstructionsList from ...rebrickable_image import RebrickableImage from ...retired_list import BrickRetiredList -from ...set_checkbox import BrickSetCheckbox -from ...set_checkbox_list import BrickSetCheckboxList +from ...set_status import BrickSetStatus +from ...set_status_list import BrickSetStatusList from ...sql_counter import BrickCounter from ...sql import BrickSQL from ...theme_list import BrickThemeList @@ -24,11 +24,11 @@ admin_page = Blueprint('admin', __name__, url_prefix='/admin') @login_required @exception_handler(__file__) def admin() -> str: - brickset_checkboxes: list[BrickSetCheckbox] = [] database_counters: list[BrickCounter] = [] database_exception: Exception | None = None database_upgrade_needed: bool = False database_version: int = -1 + metadata_statuses: list[BrickSetStatus] = [] nil_minifigure_name: str = '' nil_minifigure_url: str = '' nil_part_name: str = '' @@ -41,7 +41,7 @@ def admin() -> str: database_version = database.version database_counters = BrickSQL().count_records() - brickset_checkboxes = BrickSetCheckboxList().list(all=True) + metadata_statuses = BrickSetStatusList().list(all=True) except Exception as e: database_exception = e @@ -62,38 +62,38 @@ def admin() -> str: 'PARTS_FOLDER' ) - open_checkbox = request.args.get('open_checkbox', None) 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_status = request.args.get('open_status', None) open_theme = request.args.get('open_theme', None) open_database = ( - open_checkbox is None and open_image is None and open_instructions is None and open_logout is None and open_retired is None and + open_status is None and open_theme is None ) return render_template( 'admin.html', configuration=BrickConfigurationList.list(), - brickset_checkboxes=brickset_checkboxes, - checkbox_error=request.args.get('checkbox_error'), + status_error=request.args.get('status_error'), database_counters=database_counters, database_error=request.args.get('database_error'), database_exception=database_exception, database_upgrade_needed=database_upgrade_needed, database_version=database_version, instructions=BrickInstructionsList(), + metadata_statuses=metadata_statuses, 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_checkbox=open_checkbox, + open_status=open_status, open_database=open_database, open_image=open_image, open_instructions=open_instructions, diff --git a/bricktracker/views/admin/checkbox.py b/bricktracker/views/admin/checkbox.py deleted file mode 100644 index 6db6c5d..0000000 --- a/bricktracker/views/admin/checkbox.py +++ /dev/null @@ -1,98 +0,0 @@ -from flask import ( - Blueprint, - jsonify, - redirect, - request, - render_template, - url_for, -) -from flask_login import login_required -from werkzeug.wrappers.response import Response - -from ..exceptions import exception_handler -from ...reload import reload -from ...set_checkbox import BrickSetCheckbox - -admin_checkbox_page = Blueprint( - 'admin_checkbox', - __name__, - url_prefix='/admin/checkbox' -) - - -# Add a checkbox -@admin_checkbox_page.route('/add', methods=['POST']) -@login_required -@exception_handler( - __file__, - post_redirect='admin.admin', - error_name='checkbox_error', - open_checkbox=True -) -def add() -> Response: - BrickSetCheckbox().from_form(request.form).insert() - - reload() - - return redirect(url_for('admin.admin', open_checkbox=True)) - - -# Delete the checkbox -@admin_checkbox_page.route('/delete', methods=['GET']) -@login_required -@exception_handler(__file__) -def delete(*, id: str) -> str: - return render_template( - 'admin.html', - delete_checkbox=True, - checkbox=BrickSetCheckbox().select_specific(id), - error=request.args.get('checkbox_error') - ) - - -# Actually delete the checkbox -@admin_checkbox_page.route('/delete', methods=['POST']) -@login_required -@exception_handler( - __file__, - post_redirect='admin_checkbox.delete', - error_name='checkbox_error' -) -def do_delete(*, id: str) -> Response: - checkbox = BrickSetCheckbox().select_specific(id) - checkbox.delete() - - reload() - - return redirect(url_for('admin.admin', open_checkbox=True)) - - -# Change the field of a checkbox -@admin_checkbox_page.route('//field/', methods=['POST']) -@login_required -@exception_handler(__file__, json=True) -def update_field(*, id: str, name: str) -> Response: - checkbox = BrickSetCheckbox().select_specific(id) - value = checkbox.update_field(name, json=request.json) - - reload() - - return jsonify({'value': value}) - - -# Rename the checkbox -@admin_checkbox_page.route('/rename', methods=['POST']) -@login_required -@exception_handler( - __file__, - post_redirect='admin.admin', - error_name='checkbox_error', - open_checkbox=True -) -def rename(*, id: str) -> Response: - checkbox = BrickSetCheckbox().select_specific(id) - checkbox.from_form(request.form).rename() - - reload() - - return redirect(url_for('admin.admin', open_checkbox=True)) diff --git a/bricktracker/views/admin/status.py b/bricktracker/views/admin/status.py new file mode 100644 index 0000000..8178d69 --- /dev/null +++ b/bricktracker/views/admin/status.py @@ -0,0 +1,98 @@ +from flask import ( + Blueprint, + jsonify, + redirect, + request, + render_template, + url_for, +) +from flask_login import login_required +from werkzeug.wrappers.response import Response + +from ..exceptions import exception_handler +from ...reload import reload +from ...set_status import BrickSetStatus + +admin_status_page = Blueprint( + 'admin_status', + __name__, + url_prefix='/admin/status' +) + + +# Add a metadata status +@admin_status_page.route('/add', methods=['POST']) +@login_required +@exception_handler( + __file__, + post_redirect='admin.admin', + error_name='status_error', + open_status=True +) +def add() -> Response: + BrickSetStatus().from_form(request.form).insert() + + reload() + + return redirect(url_for('admin.admin', open_status=True)) + + +# Delete the metadata status +@admin_status_page.route('/delete', methods=['GET']) +@login_required +@exception_handler(__file__) +def delete(*, id: str) -> str: + return render_template( + 'admin.html', + delete_status=True, + status=BrickSetStatus().select_specific(id), + error=request.args.get('status_error') + ) + + +# Actually delete the metadata status +@admin_status_page.route('/delete', methods=['POST']) +@login_required +@exception_handler( + __file__, + post_redirect='admin_status.delete', + error_name='status_error' +) +def do_delete(*, id: str) -> Response: + status = BrickSetStatus().select_specific(id) + status.delete() + + reload() + + return redirect(url_for('admin.admin', open_status=True)) + + +# Change the field of a metadata status +@admin_status_page.route('//field/', methods=['POST']) +@login_required +@exception_handler(__file__, json=True) +def update_field(*, id: str, name: str) -> Response: + status = BrickSetStatus().select_specific(id) + value = status.update_field(name, json=request.json) + + reload() + + return jsonify({'value': value}) + + +# Rename the metadata status +@admin_status_page.route('/rename', methods=['POST']) +@login_required +@exception_handler( + __file__, + post_redirect='admin.admin', + error_name='status_error', + open_status=True +) +def rename(*, id: str) -> Response: + status = BrickSetStatus().select_specific(id) + status.from_form(request.form).rename() + + reload() + + return redirect(url_for('admin.admin', open_status=True)) diff --git a/bricktracker/views/index.py b/bricktracker/views/index.py index c1f0811..3e3a880 100644 --- a/bricktracker/views/index.py +++ b/bricktracker/views/index.py @@ -2,7 +2,7 @@ from flask import Blueprint, render_template from .exceptions import exception_handler from ..minifigure_list import BrickMinifigureList -from ..set_checkbox_list import BrickSetCheckboxList +from ..set_status_list import BrickSetStatusList from ..set_list import BrickSetList index_page = Blueprint('index', __name__) @@ -16,5 +16,5 @@ def index() -> str: 'index.html', brickset_collection=BrickSetList().last(), minifigure_collection=BrickMinifigureList().last(), - brickset_checkboxes=BrickSetCheckboxList().list(), + brickset_statuses=BrickSetStatusList().list(), ) diff --git a/bricktracker/views/set.py b/bricktracker/views/set.py index bb3c234..17fcff9 100644 --- a/bricktracker/views/set.py +++ b/bricktracker/views/set.py @@ -16,7 +16,7 @@ from .exceptions import exception_handler from ..minifigure import BrickMinifigure from ..part import BrickPart from ..set import BrickSet -from ..set_checkbox_list import BrickSetCheckboxList +from ..set_status_list import BrickSetStatusList from ..set_list import BrickSetList from ..socket import MESSAGES @@ -32,19 +32,19 @@ def list() -> str: return render_template( 'sets.html', collection=BrickSetList().all(), - brickset_checkboxes=BrickSetCheckboxList().list(), + brickset_statuses=BrickSetStatusList().list(), ) -# Change the status of a checkbox +# Change the status of a status @set_page.route('//status/', methods=['POST']) @login_required @exception_handler(__file__, json=True) def update_status(*, id: str, metadata_id: str) -> Response: brickset = BrickSet().select_light(id) - checkbox = BrickSetCheckboxList().get(metadata_id) + status = BrickSetStatusList().get(metadata_id) - state = checkbox.update_set_state(brickset, request.json) + state = status.update_set_state(brickset, request.json) return jsonify({'value': state}) @@ -97,7 +97,7 @@ def details(*, id: str) -> str: 'set.html', item=BrickSet().select_specific(id), open_instructions=request.args.get('open_instructions'), - brickset_checkboxes=BrickSetCheckboxList().list(all=True), + brickset_statuses=BrickSetStatusList().list(all=True), ) diff --git a/docs/DOCS.md b/docs/DOCS.md index 450ca29..2da6213 100644 --- a/docs/DOCS.md +++ b/docs/DOCS.md @@ -14,7 +14,7 @@ This page helps you navigate the documentation of BrickTracker. - [First steps](first-steps.md) - [Managing your sets](set.md) -- [Managing your set checkboxes](checkbox.md) +- [Managing your set statuses](set-statuses.md) ## Specific procedures diff --git a/docs/checkbox.md b/docs/checkbox.md deleted file mode 100644 index 3071e67..0000000 --- a/docs/checkbox.md +++ /dev/null @@ -1,58 +0,0 @@ -# Manage your set chechboxes - -> **Note** -> The following page is based on version `1.1.0` of BrickTracker. - -They are useful to store "yes/no" info about a set and quickly set it. Once clicked the change is immediatly stored in the database. A visual indicator tells you the change was succesful. - -![](images/checkbox-01.png) - -## Default checkboxes - -The original version of BrickTracker defined the following checkboxes - -- Minifigures are collected -- Set is checked -- Set is collected and boxed - -## Visibility - -The checkboxes are **never visible** on the front page. The display here tries to be as minimalistic as possible. - -Prior to version `1.1.0`, the checkboxes were visible both on the Grid view (**Sets**) and the details of a set. - -![](images/checkbox-02.png) -![](images/checkbox-03.png) - -From version `1.1.0`, it is possible to decide if a checkbox is visible from the Grid or not. It will always be visible in a set details. - -### Change the visibility of a checkbox - -To change the visibility of a checkbox, head to the **Admin page** and open the **Checkboxes** section. - -![](images/checkbox-04.png) - -Simply click on the **Displayed on the Set Grid** checkbox to select whether it is displayed or not. The change is immediately saved to the database. - -![](images/checkbox-05.png) - -In this example, we have decided to have no checkbox visible on the Grid view. - -![](images/checkbox-06.png) - -## Management - -Starting version `1.1.0`, you can manage the checkboxes for the **Checkboxes** section of the **Admin page**. - -![](images/checkbox-04.png) - -From there you can do the following: - -- Add a new checkbox: use the last line of the list and press the **Add** button -- Rename an existing checkbox: use the **Name** field to change the name and press the **Rename** button -- Change the Grid display of an existing checkbox: tick or untick the **Displayed on the Set Grid** checkbox -- Delete an existing checkbox: use the **Delete** button and confirm on the following screen - -It is possible to delete all the checkboxes, they are an optional component of a set. - -![](images/checkbox-07.png) diff --git a/docs/images/checkbox-01.png b/docs/images/status-01.png similarity index 100% rename from docs/images/checkbox-01.png rename to docs/images/status-01.png diff --git a/docs/images/checkbox-02.png b/docs/images/status-02.png similarity index 100% rename from docs/images/checkbox-02.png rename to docs/images/status-02.png diff --git a/docs/images/checkbox-03.png b/docs/images/status-03.png similarity index 100% rename from docs/images/checkbox-03.png rename to docs/images/status-03.png diff --git a/docs/images/checkbox-04.png b/docs/images/status-04.png similarity index 100% rename from docs/images/checkbox-04.png rename to docs/images/status-04.png diff --git a/docs/images/checkbox-05.png b/docs/images/status-05.png similarity index 100% rename from docs/images/checkbox-05.png rename to docs/images/status-05.png diff --git a/docs/images/checkbox-06.png b/docs/images/status-06.png similarity index 100% rename from docs/images/checkbox-06.png rename to docs/images/status-06.png diff --git a/docs/images/checkbox-07.png b/docs/images/status-07.png similarity index 100% rename from docs/images/checkbox-07.png rename to docs/images/status-07.png diff --git a/docs/set-statuses.md b/docs/set-statuses.md new file mode 100644 index 0000000..8739b41 --- /dev/null +++ b/docs/set-statuses.md @@ -0,0 +1,67 @@ +# Manage your set statuses + +> **Note** +> The following page is based on version `1.1.0` of BrickTracker. + +> **Note** +> On version `1.2.0`, this feature has been renommed from `Checkboxes` to `Set statuses`. It works exactly the same. + +They are useful to store "yes/no" info about a set and quickly set it. Once clicked the change is immediatly stored in the database. A visual indicator tells you the change was succesful. + +![](images/status-01.png) + +## Default statuses + +The original version of BrickTracker defined the following statuses + +- Minifigures are collected +- Set is checked +- Set is collected and boxed + +## Visibility + +The statuses are **never visible** on the front page. The display here tries to be as minimalistic as possible. + +Prior to version `1.1.0`, the statuses were visible both on the Grid view (**Sets**) and the details of a set. + +![](images/status-02.png) +![](images/status-03.png) + +From version `1.1.0`, it is possible to decide if a status is visible from the Grid or not. It will always be visible in a set details. + +### Change the visibility of a status + +> **Note** +> On version `1.2.0`, the Admin page section has been renamed from `Checkboxes` to `Set statuses`. It works exactly the same. + +To change the visibility of a status, head to the **Admin page** and open the **Set statuses** section. + +![](images/status-04.png) + +Simply click on the **Displayed on the Set Grid** status to select whether it is displayed or not. The change is immediately saved to the database. + +![](images/status-05.png) + +In this example, we have decided to have no status visible on the Grid view. + +![](images/status-06.png) + +## Management + +> **Note** +> On version `1.2.0`, the Admin page section has been renamed from `Checkboxes` to `Set statuses`. It works exactly the same. + +Starting version `1.1.0`, you can manage the set statuses for the **Set statuses** section of the **Admin page**. + +![](images/status-04.png) + +From there you can do the following: + +- Add a new set status: use the last line of the list and press the **Add** button +- Rename an existing set status: use the **Name** field to change the name and press the **Rename** button +- Change the Grid display of an existing status: tick or untick the **Displayed on the Set Grid** checkbox +- Delete an existing set status: use the **Delete** button and confirm on the following screen + +It is possible to delete all the set statuses, they are an optional component of a set. + +![](images/status-07.png) diff --git a/templates/admin.html b/templates/admin.html index dc87256..b2a54f3 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -12,8 +12,8 @@
Administration
- {% if delete_checkbox %} - {% include 'admin/checkbox/delete.html' %} + {% if delete_status %} + {% include 'admin/status/delete.html' %} {% elif delete_database %} {% include 'admin/database/delete.html' %} {% elif drop_database %} @@ -30,7 +30,7 @@ {% endif %} {% include 'admin/theme.html' %} {% include 'admin/retired.html' %} - {% include 'admin/checkbox.html' %} + {% include 'admin/status.html' %} {% include 'admin/database.html' %} {% include 'admin/configuration.html' %} {% endif %} diff --git a/templates/admin/checkbox.html b/templates/admin/status.html similarity index 54% rename from templates/admin/checkbox.html rename to templates/admin/status.html index 22a3215..a73462a 100644 --- a/templates/admin/checkbox.html +++ b/templates/admin/status.html @@ -1,42 +1,42 @@ {% import 'macro/accordion.html' as accordion %} -{{ accordion.header('Checkboxes', 'checkbox', 'admin', expanded=open_checkbox, icon='checkbox-line', class='p-0') }} -{% if checkbox_error %}{% endif %} +{{ accordion.header('Set statuses', 'status', 'admin', expanded=open_status, icon='checkbox-line', class='p-0') }} +{% if status_error %}{% endif %}
    - {% if brickset_checkboxes | length %} - {% for checkbox in brickset_checkboxes %} + {% if metadata_statuses | length %} + {% for status in metadata_statuses %}
  • -
    +
    - +
    Name
    - +
    - -
  • {% endfor %} {% else %} -
  • No checkbox found.
  • +
  • No status found.
  • {% endif %}
  • -
    +
    diff --git a/templates/admin/checkbox/delete.html b/templates/admin/status/delete.html similarity index 53% rename from templates/admin/checkbox/delete.html rename to templates/admin/status/delete.html index 49d507a..31998c4 100644 --- a/templates/admin/checkbox/delete.html +++ b/templates/admin/status/delete.html @@ -1,25 +1,25 @@ {% import 'macro/accordion.html' as accordion %} -{{ accordion.header('Checkbox danger zone', 'checkbox-danger', 'admin', expanded=true, danger=true, class='text-end') }} - +{{ accordion.header('Set statuses danger zone', 'status-danger', 'admin', expanded=true, danger=true, class='text-end') }} + {% if error %}{% endif %} - +
    Name
    - +
    - + Displayed on the Set Grid

    - Back to the admin - + Back to the admin + {{ accordion.footer() }} diff --git a/templates/set/card.html b/templates/set/card.html index 6a658c9..fea4fc0 100644 --- a/templates/set/card.html +++ b/templates/set/card.html @@ -8,7 +8,7 @@ data-index="{{ index }}" data-number="{{ item.fields.set }}" data-name="{{ item.fields.name | lower }}" data-parts="{{ item.fields.number_of_parts }}" data-year="{{ item.fields.year }}" data-theme="{{ item.theme.name | lower }}" data-minifigures="{{ item.fields.total_minifigures }}" data-has-minifigures="{{ (item.fields.total_minifigures > 0) | int }}" data-has-missing="{{ (item.fields.total_missing > 0) | int }}" data-has-missing-instructions="{{ (not (item.instructions | length)) | int }}" data-missing="{{ item.fields.total_missing }}" - {% for checkbox in brickset_checkboxes %}data-{{ checkbox.as_dataset() }}="{{ item.fields[checkbox.as_column()] }}" {% endfor %} + {% for status in brickset_statuses %}data-{{ status.as_dataset() }}="{{ item.fields[status.as_column()] }}" {% endfor %} {% endif %} > {{ card.header(item, item.fields.name, solo=solo, identifier=item.fields.set) }} @@ -26,11 +26,11 @@ {{ badge.rebrickable(item, solo=solo, last=last) }} {% endif %}
    - {% if not tiny and brickset_checkboxes | length %} + {% if not tiny and brickset_statuses | length %}
      - {% for checkbox in brickset_checkboxes %} + {% for status in brickset_statuses %}
    • - {{ form.checkbox(checkbox.as_dataset(), item.fields.id, checkbox.fields.name, checkbox.url_for_set_state(item.fields.id), item.fields[checkbox.as_column()], delete=delete) }} + {{ form.checkbox(status.as_dataset(), item.fields.id, status.fields.name, status.url_for_set_state(item.fields.id), item.fields[status.as_column()], delete=delete) }}
    • {% endfor %}
    diff --git a/templates/sets.html b/templates/sets.html index c62d3f3..c43925f 100644 --- a/templates/sets.html +++ b/templates/sets.html @@ -22,9 +22,9 @@ - {% for checkbox in brickset_checkboxes %} - - + {% for status in brickset_statuses %} + + {% endfor %}