forked from FrederikBaerentsen/BrickTracker
Add a refresh mode for sets
This commit is contained in:
@@ -20,7 +20,7 @@ class BrickMinifigure(RebrickableMinifigure):
|
||||
select_query: str = 'minifigure/select/specific'
|
||||
|
||||
# Import a minifigure into the database
|
||||
def download(self, socket: 'BrickSocket') -> bool:
|
||||
def download(self, socket: 'BrickSocket', refresh: bool = False) -> bool:
|
||||
if self.brickset is None:
|
||||
raise ErrorException('Importing a minifigure from Rebrickable outside of a set is not supported') # noqa: E501
|
||||
|
||||
@@ -33,8 +33,9 @@ class BrickMinifigure(RebrickableMinifigure):
|
||||
)
|
||||
)
|
||||
|
||||
# Insert into database
|
||||
self.insert(commit=False)
|
||||
if not refresh:
|
||||
# Insert into database
|
||||
self.insert(commit=False)
|
||||
|
||||
# Insert the rebrickable set into database
|
||||
self.insert_rebrickable()
|
||||
@@ -43,7 +44,8 @@ class BrickMinifigure(RebrickableMinifigure):
|
||||
if not BrickPartList.download(
|
||||
socket,
|
||||
self.brickset,
|
||||
minifigure=self
|
||||
minifigure=self,
|
||||
refresh=refresh
|
||||
):
|
||||
return False
|
||||
|
||||
|
||||
@@ -134,7 +134,13 @@ class BrickMinifigureList(BrickRecordList[BrickMinifigure]):
|
||||
|
||||
# Import the minifigures from Rebrickable
|
||||
@staticmethod
|
||||
def download(socket: 'BrickSocket', brickset: 'BrickSet', /) -> bool:
|
||||
def download(
|
||||
socket: 'BrickSocket',
|
||||
brickset: 'BrickSet',
|
||||
/,
|
||||
*,
|
||||
refresh: bool = False
|
||||
) -> bool:
|
||||
try:
|
||||
socket.auto_progress(
|
||||
message='Set {set}: loading minifigures from Rebrickable'.format( # noqa: E501
|
||||
@@ -157,7 +163,7 @@ class BrickMinifigureList(BrickRecordList[BrickMinifigure]):
|
||||
|
||||
# Process each minifigure
|
||||
for minifigure in minifigures:
|
||||
if not minifigure.download(socket):
|
||||
if not minifigure.download(socket, refresh=refresh):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -34,7 +34,7 @@ class BrickPart(RebrickablePart):
|
||||
self.kind = 'Set'
|
||||
|
||||
# Import a part into the database
|
||||
def download(self, socket: 'BrickSocket') -> bool:
|
||||
def download(self, socket: 'BrickSocket', refresh: bool = False) -> bool:
|
||||
if self.brickset is None:
|
||||
raise ErrorException('Importing a part from Rebrickable outside of a set is not supported') # noqa: E501
|
||||
|
||||
@@ -48,8 +48,9 @@ class BrickPart(RebrickablePart):
|
||||
)
|
||||
)
|
||||
|
||||
# Insert into database
|
||||
self.insert(commit=False)
|
||||
if not refresh:
|
||||
# Insert into database
|
||||
self.insert(commit=False)
|
||||
|
||||
# Insert the rebrickable set into database
|
||||
self.insert_rebrickable()
|
||||
|
||||
@@ -139,6 +139,7 @@ class BrickPartList(BrickRecordList[BrickPart]):
|
||||
/,
|
||||
*,
|
||||
minifigure: 'BrickMinifigure | None' = None,
|
||||
refresh: bool = False
|
||||
) -> bool:
|
||||
if minifigure is not None:
|
||||
identifier = minifigure.fields.figure
|
||||
@@ -174,7 +175,7 @@ class BrickPartList(BrickRecordList[BrickPart]):
|
||||
|
||||
# Process each part
|
||||
for part in inventory:
|
||||
if not part.download(socket):
|
||||
if not part.download(socket, refresh=refresh):
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
|
||||
@@ -38,27 +38,22 @@ class RebrickableMinifigure(BrickRecord):
|
||||
self.ingest(record)
|
||||
|
||||
# Insert the minifigure from Rebrickable
|
||||
def insert_rebrickable(self, /) -> bool:
|
||||
def insert_rebrickable(self, /) -> None:
|
||||
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(
|
||||
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
|
||||
if not current_app.config['USE_REMOTE_IMAGES']:
|
||||
RebrickableImage(
|
||||
self.brickset,
|
||||
minifigure=self,
|
||||
).download()
|
||||
|
||||
# Return a dict with common SQL parameters for a minifigure
|
||||
def sql_parameters(self, /) -> dict[str, Any]:
|
||||
|
||||
@@ -48,28 +48,23 @@ class RebrickablePart(BrickRecord):
|
||||
self.ingest(record)
|
||||
|
||||
# Insert the part from Rebrickable
|
||||
def insert_rebrickable(self, /) -> bool:
|
||||
def insert_rebrickable(self, /) -> None:
|
||||
if self.brickset is None:
|
||||
raise ErrorException('Importing a part from Rebrickable outside of a set is not supported') # noqa: E501
|
||||
|
||||
# Insert the Rebrickable part to the database
|
||||
rows, _ = self.insert(
|
||||
self.insert(
|
||||
commit=False,
|
||||
no_defer=True,
|
||||
override_query=RebrickablePart.insert_query
|
||||
)
|
||||
|
||||
inserted = rows > 0
|
||||
|
||||
if inserted:
|
||||
if not current_app.config['USE_REMOTE_IMAGES']:
|
||||
RebrickableImage(
|
||||
self.brickset,
|
||||
minifigure=self.minifigure,
|
||||
part=self,
|
||||
).download()
|
||||
|
||||
return inserted
|
||||
if not current_app.config['USE_REMOTE_IMAGES']:
|
||||
RebrickableImage(
|
||||
self.brickset,
|
||||
minifigure=self.minifigure,
|
||||
part=self,
|
||||
).download()
|
||||
|
||||
# Return a dict with common SQL parameters for a part
|
||||
def sql_parameters(self, /) -> dict[str, Any]:
|
||||
|
||||
@@ -47,21 +47,16 @@ class RebrickableSet(BrickRecord):
|
||||
self.ingest(record)
|
||||
|
||||
# Insert the set from Rebrickable
|
||||
def insert_rebrickable(self, /) -> bool:
|
||||
def insert_rebrickable(self, /) -> None:
|
||||
# Insert the Rebrickable set to the database
|
||||
rows, _ = self.insert(
|
||||
self.insert(
|
||||
commit=False,
|
||||
no_defer=True,
|
||||
override_query=RebrickableSet.insert_query
|
||||
)
|
||||
|
||||
inserted = rows > 0
|
||||
|
||||
if inserted:
|
||||
if not current_app.config['USE_REMOTE_IMAGES']:
|
||||
RebrickableImage(self).download()
|
||||
|
||||
return inserted
|
||||
if not current_app.config['USE_REMOTE_IMAGES']:
|
||||
RebrickableImage(self).download()
|
||||
|
||||
# Ingest a set
|
||||
def ingest(self, record: Row | dict[str, Any], /):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from sqlite3 import Row
|
||||
from typing import Any, ItemsView, Tuple
|
||||
from typing import Any, ItemsView
|
||||
|
||||
from .fields import BrickRecordFields
|
||||
from .sql import BrickSQL
|
||||
@@ -31,14 +31,14 @@ class BrickRecord(object):
|
||||
commit=True,
|
||||
no_defer=False,
|
||||
override_query: str | None = None
|
||||
) -> Tuple[int, str]:
|
||||
) -> None:
|
||||
if override_query:
|
||||
query = override_query
|
||||
else:
|
||||
query = self.insert_query
|
||||
|
||||
database = BrickSQL()
|
||||
rows, q = database.execute(
|
||||
database.execute(
|
||||
query,
|
||||
parameters=self.sql_parameters(),
|
||||
defer=not commit and not no_defer,
|
||||
@@ -47,8 +47,6 @@ class BrickRecord(object):
|
||||
if commit:
|
||||
database.commit()
|
||||
|
||||
return rows, q
|
||||
|
||||
# Shorthand to field items
|
||||
def items(self, /) -> ItemsView[str, Any]:
|
||||
return self.fields.__dict__.items()
|
||||
|
||||
+42
-17
@@ -47,21 +47,25 @@ class BrickSet(RebrickableSet):
|
||||
increment_total=True,
|
||||
)
|
||||
|
||||
# Grabbing the refresh flag
|
||||
refresh: bool = bool(data.get('refresh', False))
|
||||
|
||||
# Generate an UUID for self
|
||||
self.fields.id = str(uuid4())
|
||||
|
||||
# Insert into database
|
||||
self.insert(commit=False)
|
||||
if not refresh:
|
||||
# Insert into database
|
||||
self.insert(commit=False)
|
||||
|
||||
# Insert the rebrickable set into database
|
||||
self.insert_rebrickable()
|
||||
|
||||
# Load the inventory
|
||||
if not BrickPartList.download(socket, self):
|
||||
if not BrickPartList.download(socket, self, refresh=refresh):
|
||||
return False
|
||||
|
||||
# Load the minifigures
|
||||
if not BrickMinifigureList.download(socket, self):
|
||||
if not BrickMinifigureList.download(socket, self, refresh=refresh):
|
||||
return False
|
||||
|
||||
# Commit the transaction to the database
|
||||
@@ -74,20 +78,34 @@ class BrickSet(RebrickableSet):
|
||||
|
||||
BrickSQL().commit()
|
||||
|
||||
# Info
|
||||
logger.info('Set {set}: imported (id: {id})'.format(
|
||||
set=self.fields.set,
|
||||
id=self.fields.id,
|
||||
))
|
||||
|
||||
# Complete
|
||||
socket.complete(
|
||||
message='Set {set}: imported (<a href="{url}">Go to the set</a>)'.format( # noqa: E501
|
||||
if refresh:
|
||||
# Info
|
||||
logger.info('Set {set}: imported (id: {id})'.format(
|
||||
set=self.fields.set,
|
||||
url=self.url()
|
||||
),
|
||||
download=True
|
||||
)
|
||||
id=self.fields.id,
|
||||
))
|
||||
|
||||
# Complete
|
||||
socket.complete(
|
||||
message='Set {set}: refreshed'.format( # noqa: E501
|
||||
set=self.fields.set,
|
||||
),
|
||||
download=True
|
||||
)
|
||||
else:
|
||||
# Info
|
||||
logger.info('Set {set}: refreshed'.format(
|
||||
set=self.fields.set,
|
||||
))
|
||||
|
||||
# Complete
|
||||
socket.complete(
|
||||
message='Set {set}: imported (<a href="{url}">Go to the set</a>)'.format( # noqa: E501
|
||||
set=self.fields.set,
|
||||
url=self.url()
|
||||
),
|
||||
download=True
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
socket.fail(
|
||||
@@ -192,3 +210,10 @@ class BrickSet(RebrickableSet):
|
||||
)
|
||||
else:
|
||||
return ''
|
||||
|
||||
# Compute the url for the refresh button
|
||||
def url_for_refresh(self, /) -> str:
|
||||
return url_for(
|
||||
'set.refresh',
|
||||
id=self.fields.id,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from sqlite3 import Row
|
||||
from typing import Any, Self, Tuple
|
||||
from typing import Any, Self
|
||||
from uuid import uuid4
|
||||
|
||||
from flask import url_for
|
||||
@@ -60,7 +60,7 @@ class BrickSetCheckbox(BrickRecord):
|
||||
return self
|
||||
|
||||
# Insert into database
|
||||
def insert(self, **_) -> Tuple[int, str]:
|
||||
def insert(self, **_) -> None:
|
||||
# Generate an ID for the checkbox (with underscores to make it
|
||||
# column name friendly)
|
||||
self.fields.id = str(uuid4()).replace('-', '_')
|
||||
@@ -72,9 +72,6 @@ class BrickSetCheckbox(BrickRecord):
|
||||
displayed_on_grid=self.fields.displayed_on_grid
|
||||
)
|
||||
|
||||
# To accomodate the parent().insert we have overriden
|
||||
return 0, ''
|
||||
|
||||
# Rename the checkbox
|
||||
def rename(self, /) -> None:
|
||||
# Update the name
|
||||
|
||||
@@ -9,3 +9,9 @@ INSERT OR IGNORE INTO "rebrickable_minifigures" (
|
||||
:name,
|
||||
:image
|
||||
)
|
||||
ON CONFLICT("figure")
|
||||
DO UPDATE SET
|
||||
"number" = :number,
|
||||
"name" = :name,
|
||||
"image" = :image
|
||||
WHERE "rebrickable_minifigures"."figure" IS NOT DISTINCT FROM :figure
|
||||
|
||||
@@ -23,3 +23,16 @@ INSERT OR IGNORE INTO "rebrickable_parts" (
|
||||
:url,
|
||||
:print
|
||||
)
|
||||
ON CONFLICT("part", "color_id")
|
||||
DO UPDATE SET
|
||||
"color_name" = :color_name,
|
||||
"color_rgb" = :color_rgb,
|
||||
"color_transparent" = :color_transparent,
|
||||
"name" = :name,
|
||||
"category" = :category,
|
||||
"image" = :image,
|
||||
"image_id" = :image_id,
|
||||
"url" = :url,
|
||||
"print" = :print
|
||||
WHERE "rebrickable_parts"."part" IS NOT DISTINCT FROM :part
|
||||
AND "rebrickable_parts"."color_id" IS NOT DISTINCT FROM :color_id
|
||||
@@ -21,3 +21,15 @@ INSERT OR IGNORE INTO "rebrickable_sets" (
|
||||
:url,
|
||||
:last_modified
|
||||
)
|
||||
ON CONFLICT("set")
|
||||
DO UPDATE SET
|
||||
"number" = :number,
|
||||
"version" = :version,
|
||||
"name" = :name,
|
||||
"year" = :year,
|
||||
"theme_id" = :theme_id,
|
||||
"number_of_parts" = :number_of_parts,
|
||||
"image" = :image,
|
||||
"url" = :url,
|
||||
"last_modified" = :last_modified
|
||||
WHERE "rebrickable_sets"."set" IS NOT DISTINCT FROM :set
|
||||
|
||||
@@ -2,6 +2,7 @@ import logging
|
||||
|
||||
from flask import (
|
||||
Blueprint,
|
||||
current_app,
|
||||
jsonify,
|
||||
render_template,
|
||||
redirect,
|
||||
@@ -17,6 +18,7 @@ from ..part import BrickPart
|
||||
from ..set import BrickSet
|
||||
from ..set_checkbox_list import BrickSetCheckboxList
|
||||
from ..set_list import BrickSetList
|
||||
from ..socket import MESSAGES
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -154,3 +156,16 @@ def missing_part(
|
||||
))
|
||||
|
||||
return jsonify({'missing': missing})
|
||||
|
||||
|
||||
# Refresh a set
|
||||
@set_page.route('/<id>/refresh', methods=['GET'])
|
||||
@exception_handler(__file__)
|
||||
def refresh(*, id: str) -> str:
|
||||
return render_template(
|
||||
'refresh.html',
|
||||
item=BrickSet().select_specific(id),
|
||||
path=current_app.config['SOCKET_PATH'],
|
||||
namespace=current_app.config['SOCKET_NAMESPACE'],
|
||||
messages=MESSAGES
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user