2025-01-24 10:36:24 +01:00
|
|
|
import logging
|
|
|
|
import traceback
|
2025-01-17 11:03:00 +01:00
|
|
|
from typing import Any, Self
|
2025-01-24 10:36:24 +01:00
|
|
|
from uuid import uuid4
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-26 09:59:53 +01:00
|
|
|
from flask import current_app, url_for
|
2025-01-17 11:03:00 +01:00
|
|
|
|
|
|
|
from .exceptions import DatabaseException, NotFoundException
|
|
|
|
from .minifigure_list import BrickMinifigureList
|
|
|
|
from .part_list import BrickPartList
|
2025-01-24 10:36:24 +01:00
|
|
|
from .rebrickable_minifigures import RebrickableMinifigures
|
|
|
|
from .rebrickable_parts import RebrickableParts
|
|
|
|
from .rebrickable_set import RebrickableSet
|
|
|
|
from .set_checkbox import BrickSetCheckbox
|
|
|
|
from .set_checkbox_list import BrickSetCheckboxList
|
2025-01-17 11:03:00 +01:00
|
|
|
from .sql import BrickSQL
|
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Lego brick set
|
|
|
|
class BrickSet(RebrickableSet):
|
2025-01-17 11:03:00 +01:00
|
|
|
# Queries
|
2025-01-24 10:36:24 +01:00
|
|
|
select_query: str = 'set/select/full'
|
|
|
|
light_query: str = 'set/select/light'
|
2025-01-17 11:03:00 +01:00
|
|
|
insert_query: str = 'set/insert'
|
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Delete a set
|
|
|
|
def delete(self, /) -> None:
|
|
|
|
BrickSQL().executescript(
|
|
|
|
'set/delete/set',
|
|
|
|
id=self.fields.id
|
|
|
|
)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Import a set into the database
|
|
|
|
def download(self, data: dict[str, Any], /) -> None:
|
|
|
|
# Load the set
|
|
|
|
if not self.load(data, from_download=True):
|
|
|
|
return
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
try:
|
|
|
|
# Insert into the database
|
|
|
|
self.socket.auto_progress(
|
2025-01-27 12:04:20 +01:00
|
|
|
message='Set {set}: inserting into database'.format(
|
|
|
|
set=self.fields.set
|
2025-01-24 10:36:24 +01:00
|
|
|
),
|
|
|
|
increment_total=True,
|
|
|
|
)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Generate an UUID for self
|
|
|
|
self.fields.id = str(uuid4())
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Insert into database
|
|
|
|
self.insert(commit=False)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Execute the parent download method
|
2025-01-27 10:04:24 +01:00
|
|
|
self.insert_rebrickable()
|
2025-01-24 10:36:24 +01:00
|
|
|
|
|
|
|
# Load the inventory
|
|
|
|
RebrickableParts(self.socket, self).download()
|
|
|
|
|
|
|
|
# Load the minifigures
|
|
|
|
RebrickableMinifigures(self.socket, self).download()
|
|
|
|
|
|
|
|
# Commit the transaction to the database
|
|
|
|
self.socket.auto_progress(
|
2025-01-27 12:04:20 +01:00
|
|
|
message='Set {set}: writing to the database'.format(
|
|
|
|
set=self.fields.set
|
2025-01-24 10:36:24 +01:00
|
|
|
),
|
|
|
|
increment_total=True,
|
|
|
|
)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
BrickSQL().commit()
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Info
|
2025-01-27 12:04:20 +01:00
|
|
|
logger.info('Set {set}: imported (id: {id})'.format(
|
|
|
|
set=self.fields.set,
|
2025-01-24 10:36:24 +01:00
|
|
|
id=self.fields.id,
|
|
|
|
))
|
|
|
|
|
|
|
|
# Complete
|
|
|
|
self.socket.complete(
|
2025-01-27 12:04:20 +01:00
|
|
|
message='Set {set}: imported (<a href="{url}">Go to the set</a>)'.format( # noqa: E501
|
|
|
|
set=self.fields.set,
|
2025-01-24 10:36:24 +01:00
|
|
|
url=self.url()
|
|
|
|
),
|
|
|
|
download=True
|
|
|
|
)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
except Exception as e:
|
|
|
|
self.socket.fail(
|
2025-01-27 12:04:20 +01:00
|
|
|
message='Error while importing set {set}: {error}'.format(
|
|
|
|
set=self.fields.set,
|
2025-01-24 10:36:24 +01:00
|
|
|
error=e,
|
|
|
|
)
|
|
|
|
)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
logger.debug(traceback.format_exc())
|
2025-01-17 11:03:00 +01:00
|
|
|
|
|
|
|
# Minifigures
|
|
|
|
def minifigures(self, /) -> BrickMinifigureList:
|
|
|
|
return BrickMinifigureList().load(self)
|
|
|
|
|
|
|
|
# Parts
|
|
|
|
def parts(self, /) -> BrickPartList:
|
|
|
|
return BrickPartList().load(self)
|
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Select a light set (with an id)
|
|
|
|
def select_light(self, id: str, /) -> Self:
|
2025-01-17 11:03:00 +01:00
|
|
|
# Save the parameters to the fields
|
2025-01-24 10:36:24 +01:00
|
|
|
self.fields.id = id
|
2025-01-17 11:03:00 +01:00
|
|
|
|
|
|
|
# Load from database
|
2025-01-24 10:36:24 +01:00
|
|
|
if not self.select(override_query=self.light_query):
|
2025-01-17 11:03:00 +01:00
|
|
|
raise NotFoundException(
|
|
|
|
'Set with ID {id} was not found in the database'.format(
|
2025-01-24 10:36:24 +01:00
|
|
|
id=self.fields.id,
|
2025-01-17 11:03:00 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
return self
|
2025-01-17 11:03:00 +01:00
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Select a specific set (with an id)
|
|
|
|
def select_specific(self, id: str, /) -> Self:
|
|
|
|
# Save the parameters to the fields
|
|
|
|
self.fields.id = id
|
|
|
|
|
|
|
|
# Load from database
|
|
|
|
if not self.select(
|
|
|
|
statuses=BrickSetCheckboxList().as_columns(solo=True)
|
|
|
|
):
|
|
|
|
raise NotFoundException(
|
|
|
|
'Set with ID {id} was not found in the database'.format(
|
|
|
|
id=self.fields.id,
|
|
|
|
),
|
|
|
|
)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
|
|
|
return self
|
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Update a status
|
|
|
|
def update_status(
|
|
|
|
self,
|
|
|
|
checkbox: BrickSetCheckbox,
|
|
|
|
status: bool,
|
|
|
|
/
|
|
|
|
) -> None:
|
2025-01-17 11:03:00 +01:00
|
|
|
parameters = self.sql_parameters()
|
|
|
|
parameters['status'] = status
|
|
|
|
|
2025-01-24 10:36:24 +01:00
|
|
|
# Update the status
|
2025-01-17 11:03:00 +01:00
|
|
|
rows, _ = BrickSQL().execute_and_commit(
|
2025-01-24 10:36:24 +01:00
|
|
|
'set/update/status',
|
2025-01-17 11:03:00 +01:00
|
|
|
parameters=parameters,
|
2025-01-24 10:36:24 +01:00
|
|
|
name=checkbox.as_column(),
|
2025-01-17 11:03:00 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
if rows != 1:
|
2025-01-27 12:04:20 +01:00
|
|
|
raise DatabaseException('Could not update the status "{status}" for set {set} ({id})'.format( # noqa: E501
|
2025-01-24 10:36:24 +01:00
|
|
|
status=checkbox.fields.name,
|
2025-01-27 12:04:20 +01:00
|
|
|
set=self.fields.set,
|
2025-01-24 10:36:24 +01:00
|
|
|
id=self.fields.id,
|
2025-01-17 11:03:00 +01:00
|
|
|
))
|
|
|
|
|
|
|
|
# Self url
|
|
|
|
def url(self, /) -> str:
|
2025-01-24 10:36:24 +01:00
|
|
|
return url_for('set.details', id=self.fields.id)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
|
|
|
# Deletion url
|
|
|
|
def url_for_delete(self, /) -> str:
|
2025-01-24 10:36:24 +01:00
|
|
|
return url_for('set.delete', id=self.fields.id)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
|
|
|
# Actual deletion url
|
|
|
|
def url_for_do_delete(self, /) -> str:
|
2025-01-24 10:36:24 +01:00
|
|
|
return url_for('set.do_delete', id=self.fields.id)
|
2025-01-17 11:03:00 +01:00
|
|
|
|
|
|
|
# Compute the url for the set instructions
|
|
|
|
def url_for_instructions(self, /) -> str:
|
2025-01-26 09:59:53 +01:00
|
|
|
if (
|
|
|
|
not current_app.config['HIDE_SET_INSTRUCTIONS'] and
|
|
|
|
len(self.instructions)
|
|
|
|
):
|
2025-01-17 11:03:00 +01:00
|
|
|
return url_for(
|
|
|
|
'set.details',
|
2025-01-24 10:36:24 +01:00
|
|
|
id=self.fields.id,
|
2025-01-17 11:03:00 +01:00
|
|
|
open_instructions=True
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return ''
|