Skip to content

Commit 020cc49

Browse files
committed
fix project saving following a change in MPC frontend. resolves #227
i've also taken a stab at hardening our MPC wait timeout logic and max retries when inserting an image into its slots
1 parent 0ff44a3 commit 020cc49

File tree

2 files changed

+54
-13
lines changed

2 files changed

+54
-13
lines changed

desktop-tool/src/constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ class TargetSite:
102102
default={cardstock: cardstock.value for cardstock in Cardstocks}
103103
)
104104
# endregion
105+
# region save states
106+
saved_successfully_text: str = attr.ib(default="Saved successfully")
107+
# endregion
105108

106109
def format_url(self, url: str) -> str:
107110
return f"{self.base_url}/{url}"
@@ -161,6 +164,7 @@ class TargetSites(Enum):
161164
base_url="https://www.printerstudio.de",
162165
starting_url_route="machen/blanko-spielkarten-63x88mm-personalisieren.html",
163166
supports_foil=False,
167+
saved_successfully_text="Speicherung erfolgreich",
164168
cardstock_site_name_mapping={
165169
Cardstocks.S30: "Standard (glatt)",
166170
Cardstocks.S33: "Super (glatt)",

desktop-tool/src/driver.py

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from selenium.webdriver.remote.webdriver import WebDriver
2121
from selenium.webdriver.support.expected_conditions import (
2222
invisibility_of_element,
23+
text_to_be_present_in_element,
2324
visibility_of_element_located,
2425
)
2526
from selenium.webdriver.support.ui import Select, WebDriverWait
@@ -166,27 +167,36 @@ def switch_to_frame(self, frame: str) -> Generator[None, None, None]:
166167

167168
@alert_handler
168169
@exception_retry_skip_handler
169-
def wait(self) -> None:
170+
def wait(self) -> bool:
170171
"""
171172
Wait until the loading circle in the targeted site disappears.
173+
If the frontend locks up while loading, this function will attempt to resolve this
174+
with a page refresh (and the return value indicates if a refresh occurred).
172175
"""
173176

177+
wait_timeout_seconds = 30
174178
logging.debug("Waiting until MPC loading circle disappears...")
175179
try:
176180
wait_elem = self.driver.find_element(by=By.ID, value="sysdiv_wait")
177181
# Wait for the element to become invisible
178182
while True:
179183
try:
180-
WebDriverWait(self.driver, 100, poll_frequency=0.1).until(invisibility_of_element(wait_elem))
184+
WebDriverWait(self.driver, wait_timeout_seconds, poll_frequency=0.1).until(
185+
invisibility_of_element(wait_elem)
186+
)
181187
except sl_exc.TimeoutException:
182-
logging.debug("Timed out while waiting for the loading circle to disappear.")
183-
continue
188+
logging.info(
189+
f"Waited for longer than {wait_timeout_seconds}s for the {self.target_site.name} page "
190+
f"to respond - attempting to resolve with a page refresh..."
191+
)
192+
self.driver.refresh()
193+
return True
184194
logging.debug("The loading circle has disappeared!")
185195
break
186196
except (sl_exc.NoSuchElementException, sl_exc.NoSuchFrameException, sl_exc.WebDriverException) as e:
187197
logging.debug("Attempted to locate the loading circle but encountered an exception:")
188198
logging.debug(e)
189-
return
199+
return False
190200

191201
def set_state(self, state: str, action: Optional[str] = None) -> None:
192202
self.state = state
@@ -373,7 +383,7 @@ def upload_image(self, image: CardImage, max_tries: int = 3) -> Optional[str]:
373383
return None
374384

375385
@exception_retry_skip_handler
376-
def insert_image(self, pid: Optional[str], image: CardImage, slots: list[int]) -> None:
386+
def insert_image(self, pid: Optional[str], image: CardImage, slots: list[int], max_tries: int = 3) -> None:
377387
"""
378388
Inserts the image identified by `pid` into `slots`.
379389
"""
@@ -382,15 +392,28 @@ def insert_image(self, pid: Optional[str], image: CardImage, slots: list[int]) -
382392
self.wait_until_javascript_object_is_defined("PageLayout.prototype.applyDragPhoto")
383393

384394
if pid:
385-
logging.debug(f"Inserting {image.name} into slots {slots}...")
395+
logging.debug(f'Inserting "{image.name}" into slots {slots}...')
386396
for i, slot in enumerate(slots, start=1):
387397
logging.debug(f"Inserting into slot {slot}...")
388-
self.set_state(state=self.state, action=f"Inserting {image.name} into slot {slot+1} ({i}/{len(slots)})")
389-
# Insert the card into each slot and wait for the page to load before continuing
390-
self.execute_javascript(
391-
f'PageLayout.prototype.applyDragPhoto({self.get_element_for_slot_js(slot)}, 0, "{pid}")'
398+
self.set_state(
399+
state=self.state, action=f'Inserting "{image.name}" into slot {slot+1} ({i}/{len(slots)})'
392400
)
393-
self.wait()
401+
# Insert the card into each slot and wait for the page to load before continuing
402+
tries = 0
403+
page_refreshed_while_inserting_image = True
404+
while page_refreshed_while_inserting_image:
405+
self.execute_javascript(
406+
f'PageLayout.prototype.applyDragPhoto({self.get_element_for_slot_js(slot)}, 0, "{pid}")'
407+
)
408+
409+
page_refreshed_while_inserting_image = self.wait()
410+
tries += 1
411+
if tries >= max_tries:
412+
logging.warning(
413+
f"Attempted to insert image {bold(image.name)} {max_tries} times, "
414+
f"but no attempt succeeded! Skipping this image."
415+
)
416+
break
394417
logging.debug(f"All done inserting {image.name} into slots {slots}!")
395418
self.set_state(self.state)
396419
else:
@@ -624,6 +647,20 @@ def save_project_to_user_account(self, order: CardOrder) -> None:
624647
self.wait_until_javascript_object_is_defined("oDesign.setTemporarySave")
625648
self.execute_javascript("oDesign.setTemporarySave();")
626649
self.wait()
650+
651+
wait_timeout_seconds = 15
652+
try:
653+
WebDriverWait(self.driver, wait_timeout_seconds).until(
654+
text_to_be_present_in_element(
655+
(By.ID, "div_temporarysavestatus"), self.target_site.value.saved_successfully_text
656+
)
657+
)
658+
except sl_exc.TimeoutException:
659+
logging.info(
660+
f"Waited for longer than {wait_timeout_seconds}s for the {self.target_site.name} page to respond - "
661+
"attempting to resolve with a page refresh..."
662+
)
663+
self.driver.refresh()
627664
logging.debug("Finished saving the project to the user's account!")
628665

629666
# endregion
@@ -775,7 +812,7 @@ def execute_orders(
775812
auto_save_threshold: Optional[int],
776813
post_processing_config: Optional[ImagePostProcessingConfig],
777814
) -> None:
778-
logging.info(f"{bold(len(orders))} projects are scheduled to be auto-filled. They are:")
815+
logging.info(f"{bold(len(orders))} project/s are scheduled to be auto-filled. They are:")
779816
for i, order in enumerate(orders, start=1):
780817
logging.info(f"{i}. {bold(order.name or 'Unnamed Project')}")
781818
logging.info(" " + order.get_overview())

0 commit comments

Comments
 (0)