131 lines
3.8 KiB
Python
131 lines
3.8 KiB
Python
|
import logging
|
||
|
from sqlite3 import Row
|
||
|
from typing import Any, TYPE_CHECKING
|
||
|
|
||
|
from flask import current_app, url_for
|
||
|
|
||
|
from .exceptions import ErrorException
|
||
|
from .rebrickable_image import RebrickableImage
|
||
|
from .record import BrickRecord
|
||
|
if TYPE_CHECKING:
|
||
|
from .set import BrickSet
|
||
|
from .socket import BrickSocket
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
# A minifigure from Rebrickable
|
||
|
class RebrickableMinifigure(BrickRecord):
|
||
|
socket: 'BrickSocket'
|
||
|
brickset: 'BrickSet | None'
|
||
|
|
||
|
# Queries
|
||
|
select_query: str = 'rebrickable/minifigure/select'
|
||
|
insert_query: str = 'rebrickable/minifigure/insert'
|
||
|
|
||
|
def __init__(
|
||
|
self,
|
||
|
/,
|
||
|
*,
|
||
|
brickset: 'BrickSet | None' = None,
|
||
|
socket: 'BrickSocket | None' = None,
|
||
|
record: Row | dict[str, Any] | None = None
|
||
|
):
|
||
|
super().__init__()
|
||
|
|
||
|
# Placeholders
|
||
|
self.instructions = []
|
||
|
|
||
|
# Save the brickset
|
||
|
self.brickset = brickset
|
||
|
|
||
|
# Save the socket
|
||
|
if socket is not None:
|
||
|
self.socket = socket
|
||
|
|
||
|
# Ingest the record if it has one
|
||
|
if record is not None:
|
||
|
self.ingest(record)
|
||
|
|
||
|
# Insert the minifigure from Rebrickable
|
||
|
def insert_rebrickable(self, /) -> bool:
|
||
|
if self.brickset is None:
|
||
|
raise ErrorException('Importing a minifigure from Rebrickable outside of a set is not supported') # noqa: E501
|
||
|
|
||
|
# Insert the Rebrickable minifigure to the database
|
||
|
rows, _ = self.insert(
|
||
|
commit=False,
|
||
|
no_defer=True,
|
||
|
override_query=RebrickableMinifigure.insert_query
|
||
|
)
|
||
|
|
||
|
inserted = rows > 0
|
||
|
|
||
|
if inserted:
|
||
|
if not current_app.config['USE_REMOTE_IMAGES']:
|
||
|
RebrickableImage(
|
||
|
self.brickset,
|
||
|
minifigure=self,
|
||
|
).download()
|
||
|
|
||
|
return inserted
|
||
|
|
||
|
# Return a dict with common SQL parameters for a minifigure
|
||
|
def sql_parameters(self, /) -> dict[str, Any]:
|
||
|
parameters = super().sql_parameters()
|
||
|
|
||
|
# Supplement from the brickset
|
||
|
if self.brickset is not None:
|
||
|
if 'bricktracker_set_id' not in parameters:
|
||
|
parameters['bricktracker_set_id'] = self.brickset.fields.id
|
||
|
|
||
|
return parameters
|
||
|
|
||
|
# Self url
|
||
|
def url(self, /) -> str:
|
||
|
return url_for(
|
||
|
'minifigure.details',
|
||
|
figure=self.fields.figure,
|
||
|
)
|
||
|
|
||
|
# Compute the url for minifigure image
|
||
|
def url_for_image(self, /) -> str:
|
||
|
if not current_app.config['USE_REMOTE_IMAGES']:
|
||
|
if self.fields.image is None:
|
||
|
file = RebrickableImage.nil_minifigure_name()
|
||
|
else:
|
||
|
file = self.fields.figure
|
||
|
|
||
|
return RebrickableImage.static_url(file, 'MINIFIGURES_FOLDER')
|
||
|
else:
|
||
|
if self.fields.image is None:
|
||
|
return current_app.config['REBRICKABLE_IMAGE_NIL_MINIFIGURE']
|
||
|
else:
|
||
|
return self.fields.image
|
||
|
|
||
|
# Compute the url for the rebrickable page
|
||
|
def url_for_rebrickable(self, /) -> str:
|
||
|
if current_app.config['REBRICKABLE_LINKS']:
|
||
|
try:
|
||
|
return current_app.config['REBRICKABLE_LINK_MINIFIGURE_PATTERN'].format( # noqa: E501
|
||
|
number=self.fields.figure,
|
||
|
)
|
||
|
except Exception:
|
||
|
pass
|
||
|
|
||
|
return ''
|
||
|
|
||
|
# Normalize from Rebrickable
|
||
|
@staticmethod
|
||
|
def from_rebrickable(data: dict[str, Any], /, **_) -> dict[str, Any]:
|
||
|
# Extracting number
|
||
|
number = int(str(data['set_num'])[5:])
|
||
|
|
||
|
return {
|
||
|
'figure': str(data['set_num']),
|
||
|
'number': int(number),
|
||
|
'name': str(data['set_name']),
|
||
|
'quantity': int(data['quantity']),
|
||
|
'image': data['set_img_url'],
|
||
|
}
|