update: updated tickets enum handling
This commit is contained in:
parent
8039ab08bb
commit
f13bc8d61e
4 changed files with 133 additions and 212 deletions
|
|
@ -1,95 +1,6 @@
|
||||||
from core.models.Result import ResultError
|
from core.models.Result import Result, ResultError
|
||||||
|
|
||||||
|
|
||||||
def result_is_valid(result):
|
def result_from_exception(exception: Exception, error_type: ResultError = ResultError.UNKNOWN) -> Result:
|
||||||
if hasattr(result, 'valid'):
|
message = str(exception) or type(exception).__name__
|
||||||
return bool(result.valid)
|
return Result(valid=False, error_type=error_type, message=message)
|
||||||
if isinstance(result, dict):
|
|
||||||
return bool(result.get('valid'))
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def result_data(result):
|
|
||||||
if hasattr(result, 'data'):
|
|
||||||
return result.data
|
|
||||||
if isinstance(result, dict):
|
|
||||||
return result.get('data') or result.get('billing_code')
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def result_message(result, default='Operation failed.'):
|
|
||||||
if hasattr(result, 'message') and result.message:
|
|
||||||
return str(result.message)
|
|
||||||
if isinstance(result, dict):
|
|
||||||
return str(result.get('message') or result.get('error_code') or default)
|
|
||||||
return default
|
|
||||||
|
|
||||||
|
|
||||||
def result_error_value(result, default=ResultError.UNKNOWN.value):
|
|
||||||
error_type = None
|
|
||||||
if hasattr(result, 'error_type'):
|
|
||||||
error_type = result.error_type
|
|
||||||
elif isinstance(result, dict):
|
|
||||||
error_type = result.get('error_type') or result.get('error_code')
|
|
||||||
|
|
||||||
if error_type is None:
|
|
||||||
return default
|
|
||||||
if hasattr(error_type, 'value'):
|
|
||||||
return str(error_type.value)
|
|
||||||
return str(error_type)
|
|
||||||
|
|
||||||
|
|
||||||
def operation_failure_payload(operation, result=None, message=None, exception=None, context=None):
|
|
||||||
if exception is not None:
|
|
||||||
error_value = ResultError.UNKNOWN.value
|
|
||||||
detail = str(exception) or type(exception).__name__
|
|
||||||
else:
|
|
||||||
error_value = result_error_value(result)
|
|
||||||
detail = message or result_message(result)
|
|
||||||
|
|
||||||
title = _operation_title(operation, error_value)
|
|
||||||
return {
|
|
||||||
'operation': operation,
|
|
||||||
'title': title,
|
|
||||||
'message': detail,
|
|
||||||
'error_type': error_value,
|
|
||||||
'severity': _severity_for(error_value),
|
|
||||||
'actions': _actions_for(error_value),
|
|
||||||
'context': context or {},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _operation_title(operation, error_value):
|
|
||||||
if error_value == ResultError.CONNECTION.value:
|
|
||||||
return 'Connection Problem'
|
|
||||||
if operation == 'use_ticket' and error_value == ResultError.SUBSCRIPTION.value:
|
|
||||||
return 'Ticket Expired'
|
|
||||||
if operation == 'use_ticket':
|
|
||||||
return 'Ticket Use Failed'
|
|
||||||
if operation == 'enable_profile':
|
|
||||||
return 'Profile Enable Failed'
|
|
||||||
if operation == 'disable_profile':
|
|
||||||
return 'Profile Disable Failed'
|
|
||||||
return 'Operation Failed'
|
|
||||||
|
|
||||||
|
|
||||||
def _severity_for(error_value):
|
|
||||||
if error_value in {
|
|
||||||
ResultError.CONNECTION.value,
|
|
||||||
ResultError.SUBSCRIPTION.value,
|
|
||||||
ResultError.MISSING_FILE.value,
|
|
||||||
ResultError.MISSING_DATA.value,
|
|
||||||
}:
|
|
||||||
return 'warning'
|
|
||||||
return 'error'
|
|
||||||
|
|
||||||
|
|
||||||
def _actions_for(error_value):
|
|
||||||
if error_value == ResultError.CONNECTION.value:
|
|
||||||
return [
|
|
||||||
{'key': 'retry', 'label': 'Try Again', 'role': 'primary'},
|
|
||||||
{'key': 'cancel', 'label': 'Cancel', 'role': 'secondary'},
|
|
||||||
]
|
|
||||||
return [
|
|
||||||
{'key': 'dismiss', 'label': 'OK', 'role': 'primary'},
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,13 @@ from core.controllers.tickets.UseTicketController import (
|
||||||
do_we_use_a_random_ticket,
|
do_we_use_a_random_ticket,
|
||||||
get_unused_tickets,
|
get_unused_tickets,
|
||||||
)
|
)
|
||||||
|
from core.models.Result import Result, ResultError
|
||||||
from core.models.session.SessionProfile import SessionProfile
|
from core.models.session.SessionProfile import SessionProfile
|
||||||
from core.models.system.SystemProfile import SystemProfile
|
from core.models.system.SystemProfile import SystemProfile
|
||||||
|
|
||||||
from gui.v2.infrastructure.setup_observers import ticket_observer
|
from gui.v2.infrastructure.setup_observers import ticket_observer
|
||||||
from gui.v2.actions.database_health import GuiStorageDatabaseError
|
from gui.v2.actions.database_health import GuiStorageDatabaseError
|
||||||
|
from gui.v2.actions.operation_results import result_from_exception
|
||||||
from gui.v2.actions.profile_order import normalize_profile_order
|
from gui.v2.actions.profile_order import normalize_profile_order
|
||||||
from gui.v2.actions.profile_status import is_profile_enabled_for_gui
|
from gui.v2.actions.profile_status import is_profile_enabled_for_gui
|
||||||
from gui.v2.ui.pages.Page import Page
|
from gui.v2.ui.pages.Page import Page
|
||||||
|
|
@ -77,6 +79,8 @@ class MenuPage(Page):
|
||||||
self.button_states = {}
|
self.button_states = {}
|
||||||
self.is_system_connected = False
|
self.is_system_connected = False
|
||||||
self.profile_button_map = {}
|
self.profile_button_map = {}
|
||||||
|
self._pending_operation_name = None
|
||||||
|
self._pending_operation_profile_data = None
|
||||||
self.font_style = f"font-family: '{main_window.open_sans_family}';" if main_window.open_sans_family else ""
|
self.font_style = f"font-family: '{main_window.open_sans_family}';" if main_window.open_sans_family else ""
|
||||||
|
|
||||||
self.create_interface_elements()
|
self.create_interface_elements()
|
||||||
|
|
@ -1255,6 +1259,8 @@ class MenuPage(Page):
|
||||||
self.enabling_profile(profile_data)
|
self.enabling_profile(profile_data)
|
||||||
|
|
||||||
def enabling_profile(self, profile_data):
|
def enabling_profile(self, profile_data):
|
||||||
|
self._pending_operation_name = 'enable_profile'
|
||||||
|
self._pending_operation_profile_data = dict(profile_data)
|
||||||
self.worker = Worker(profile_data)
|
self.worker = Worker(profile_data)
|
||||||
self.worker.update_signal.connect(self.update_gui_main_thread)
|
self.worker.update_signal.connect(self.update_gui_main_thread)
|
||||||
self.worker.change_page.connect(self.change_app_page)
|
self.worker.change_page.connect(self.change_app_page)
|
||||||
|
|
@ -1265,44 +1271,73 @@ class MenuPage(Page):
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
def handle_operation_failure(self, payload):
|
def handle_operation_failure(self, payload):
|
||||||
if not isinstance(payload, dict):
|
result = self._result_from_payload(payload)
|
||||||
payload = {
|
if result.valid:
|
||||||
'title': 'Operation Failed',
|
if result.message:
|
||||||
'message': str(payload),
|
self.update_status.update_status(result.message)
|
||||||
'actions': [{'key': 'dismiss', 'label': 'OK', 'role': 'primary'}],
|
return
|
||||||
'severity': 'error',
|
|
||||||
'context': {},
|
|
||||||
}
|
|
||||||
|
|
||||||
message = str(payload.get('message') or 'The operation could not be completed.')
|
message = result.message or result.user_message()
|
||||||
self.update_status.update_status(message)
|
self.update_status.update_status(message)
|
||||||
self.boton_just.setEnabled(True)
|
self.boton_just.setEnabled(True)
|
||||||
self.boton_just_session.setEnabled(True)
|
self.boton_just_session.setEnabled(True)
|
||||||
self.disconnect_button.setEnabled(True)
|
self.disconnect_button.setEnabled(True)
|
||||||
self.disconnect_system_wide_button.setEnabled(True)
|
self.disconnect_system_wide_button.setEnabled(True)
|
||||||
|
|
||||||
|
is_actionable = result.error_type in self._operation_choices()
|
||||||
|
|
||||||
self.popup = OperationResultPopup(
|
self.popup = OperationResultPopup(
|
||||||
self,
|
self,
|
||||||
title=payload.get('title', 'Operation Failed'),
|
|
||||||
message=message,
|
message=message,
|
||||||
actions=payload.get('actions'),
|
action_button_text="Yes" if is_actionable else "OK",
|
||||||
severity=payload.get('severity', 'error'),
|
cancel_button_text="No" if is_actionable else None,
|
||||||
|
action_result=is_actionable,
|
||||||
)
|
)
|
||||||
self.popup.action_selected.connect(
|
self.popup.action_selected.connect(
|
||||||
lambda action, current_payload=payload: self.handle_operation_popup_action(action, current_payload))
|
lambda accepted, current_result=result: self.handle_operation_popup_action(accepted, current_result))
|
||||||
self.popup.show()
|
self.popup.show()
|
||||||
|
|
||||||
def handle_operation_popup_action(self, action, payload):
|
def _result_from_payload(self, payload):
|
||||||
if action != 'retry':
|
if isinstance(payload, Result):
|
||||||
|
return payload
|
||||||
|
if isinstance(payload, Exception):
|
||||||
|
return result_from_exception(payload)
|
||||||
|
return Result(
|
||||||
|
valid=False,
|
||||||
|
error_type=ResultError.UNKNOWN,
|
||||||
|
message=str(payload) or 'The operation could not be completed.',
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle_operation_popup_action(self, accepted, result):
|
||||||
|
if not accepted:
|
||||||
return
|
return
|
||||||
context = payload.get('context') or {}
|
self._action_for_result(result)(result)
|
||||||
profile_data = context.get('profile_data')
|
|
||||||
|
def _action_for_result(self, result):
|
||||||
|
return self._operation_choices().get(result.error_type, self._dismiss_operation_result)
|
||||||
|
|
||||||
|
def _operation_choices(self):
|
||||||
|
CHOICES = {
|
||||||
|
ResultError.CONNECTION: self._retry_pending_operation,
|
||||||
|
ResultError.SUBSCRIPTION: self._handle_expired_ticket_result,
|
||||||
|
}
|
||||||
|
return CHOICES
|
||||||
|
|
||||||
|
def _retry_pending_operation(self, result):
|
||||||
|
profile_data = self._pending_operation_profile_data
|
||||||
if not isinstance(profile_data, dict) or 'id' not in profile_data:
|
if not isinstance(profile_data, dict) or 'id' not in profile_data:
|
||||||
self.update_status.update_status('Retry is unavailable for this operation.')
|
self.update_status.update_status('Retry is unavailable for this operation.')
|
||||||
return
|
return
|
||||||
self.update_status.update_status('Retrying...')
|
self.update_status.update_status('Retrying...')
|
||||||
self.enabling_profile(dict(profile_data))
|
self.enabling_profile(dict(profile_data))
|
||||||
|
|
||||||
|
def _handle_expired_ticket_result(self, result):
|
||||||
|
self.update_status.update_status(result.message or 'Ticket expired.')
|
||||||
|
self._route_to_billing_entry()
|
||||||
|
|
||||||
|
def _dismiss_operation_result(self, result):
|
||||||
|
self.update_status.update_status(result.message or 'The operation could not be completed.')
|
||||||
|
|
||||||
def show_ticket_data_loss_popup(self, ticket_number, billing_code):
|
def show_ticket_data_loss_popup(self, ticket_number, billing_code):
|
||||||
self.custom_window.navigator.navigate("menu")
|
self.custom_window.navigator.navigate("menu")
|
||||||
self.update_status.update_status('Critical: invalid billing code from ticket.')
|
self.update_status.update_status('Critical: invalid billing code from ticket.')
|
||||||
|
|
|
||||||
|
|
@ -12,21 +12,23 @@ from PyQt6.QtWidgets import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from gui.v2.ui.styles.styles import (
|
from gui.v2.ui.styles.styles import (
|
||||||
|
POPUP_ACTION_BUTTON_RED_QSS,
|
||||||
POPUP_BG_QSS,
|
POPUP_BG_QSS,
|
||||||
POPUP_CANCEL_BUTTON_QSS,
|
POPUP_CANCEL_BUTTON_QSS,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class OperationResultPopup(QDialog):
|
class OperationResultPopup(QDialog):
|
||||||
action_selected = pyqtSignal(str)
|
action_selected = pyqtSignal(bool)
|
||||||
|
|
||||||
def __init__(self, parent=None, title="", message="", actions=None, severity="error"):
|
def __init__(self, parent=None, message="", title="Operation Failed", action_button_text="Yes", cancel_button_text="No", action_result=True):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.parent_window = parent
|
self.parent_window = parent
|
||||||
self.title_text = title or "Operation Failed"
|
self.title_text = title or "Operation Failed"
|
||||||
self.message = message or "The operation could not be completed."
|
self.message = message or "The operation could not be completed."
|
||||||
self.actions = actions or [{'key': 'dismiss', 'label': 'OK', 'role': 'primary'}]
|
self.action_button_text = action_button_text
|
||||||
self.severity = severity
|
self.cancel_button_text = cancel_button_text
|
||||||
|
self.action_result = action_result
|
||||||
self._completed = False
|
self._completed = False
|
||||||
self._use_parent_local_geometry = QGuiApplication.platformName().lower().startswith("wayland")
|
self._use_parent_local_geometry = QGuiApplication.platformName().lower().startswith("wayland")
|
||||||
self.initUI()
|
self.initUI()
|
||||||
|
|
@ -58,7 +60,7 @@ class OperationResultPopup(QDialog):
|
||||||
|
|
||||||
title_label = QLabel(self.title_text)
|
title_label = QLabel(self.title_text)
|
||||||
title_label.setFont(QFont("Arial", 18, QFont.Weight.Bold))
|
title_label.setFont(QFont("Arial", 18, QFont.Weight.Bold))
|
||||||
title_label.setStyleSheet(f"color: {self._title_color()}; background: transparent; border: none;")
|
title_label.setStyleSheet("color: #d62828; background: transparent; border: none;")
|
||||||
title_label.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
|
title_label.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
|
||||||
title_label.setMinimumWidth(0)
|
title_label.setMinimumWidth(0)
|
||||||
top_row.addWidget(title_label, 1)
|
top_row.addWidget(title_label, 1)
|
||||||
|
|
@ -78,7 +80,7 @@ class OperationResultPopup(QDialog):
|
||||||
color: #d62828;
|
color: #d62828;
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
close_button.clicked.connect(lambda: self._choose('cancel'))
|
close_button.clicked.connect(lambda: self._choose(False))
|
||||||
top_row.addWidget(close_button, 0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop)
|
top_row.addWidget(close_button, 0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop)
|
||||||
|
|
||||||
content_layout.addLayout(top_row)
|
content_layout.addLayout(top_row)
|
||||||
|
|
@ -106,64 +108,39 @@ class OperationResultPopup(QDialog):
|
||||||
|
|
||||||
button_row = QHBoxLayout()
|
button_row = QHBoxLayout()
|
||||||
button_row.addStretch()
|
button_row.addStretch()
|
||||||
for action in self.actions:
|
|
||||||
button = QPushButton(action.get('label', 'OK'))
|
if self.cancel_button_text is not None:
|
||||||
button.setFixedSize(max(110, min(180, 22 + len(action.get('label', 'OK')) * 8)), 42)
|
cancel_button = QPushButton(self.cancel_button_text)
|
||||||
button.setFont(QFont("Arial", 11, QFont.Weight.Bold))
|
cancel_button.setFixedSize(max(110, min(180, 22 + len(self.cancel_button_text) * 8)), 42)
|
||||||
button.setCursor(Qt.CursorShape.PointingHandCursor)
|
cancel_button.setFont(QFont("Arial", 11, QFont.Weight.Bold))
|
||||||
button.setStyleSheet(self._button_style(action.get('role', 'primary')))
|
cancel_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
button.clicked.connect(lambda checked=False, key=action.get('key', 'dismiss'): self._choose(key))
|
cancel_button.setStyleSheet(POPUP_CANCEL_BUTTON_QSS)
|
||||||
button_row.addWidget(button)
|
cancel_button.clicked.connect(lambda: self._choose(False))
|
||||||
|
button_row.addWidget(cancel_button)
|
||||||
|
|
||||||
|
action_button = QPushButton(self.action_button_text)
|
||||||
|
action_button.setFixedSize(max(110, min(180, 22 + len(self.action_button_text) * 8)), 42)
|
||||||
|
action_button.setFont(QFont("Arial", 11, QFont.Weight.Bold))
|
||||||
|
action_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
|
action_button.setStyleSheet(POPUP_ACTION_BUTTON_RED_QSS)
|
||||||
|
action_button.clicked.connect(lambda: self._choose(self.action_result))
|
||||||
|
button_row.addWidget(action_button)
|
||||||
content_layout.addLayout(button_row)
|
content_layout.addLayout(button_row)
|
||||||
|
|
||||||
if not self._use_parent_local_geometry:
|
if not self._use_parent_local_geometry:
|
||||||
self.setWindowModality(Qt.WindowModality.ApplicationModal)
|
self.setWindowModality(Qt.WindowModality.ApplicationModal)
|
||||||
|
|
||||||
def _title_color(self):
|
def _choose(self, accepted):
|
||||||
if self.severity == 'warning':
|
|
||||||
return '#d97706'
|
|
||||||
return '#d62828'
|
|
||||||
|
|
||||||
def _button_style(self, role):
|
|
||||||
if role == 'secondary':
|
|
||||||
return POPUP_CANCEL_BUTTON_QSS
|
|
||||||
if self.severity == 'warning':
|
|
||||||
return """
|
|
||||||
QPushButton {
|
|
||||||
background-color: #f59e0b;
|
|
||||||
border: none;
|
|
||||||
color: white;
|
|
||||||
border-radius: 5px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background-color: #d97706;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
return """
|
|
||||||
QPushButton {
|
|
||||||
background-color: #d62828;
|
|
||||||
border: none;
|
|
||||||
color: white;
|
|
||||||
border-radius: 5px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
QPushButton:hover {
|
|
||||||
background-color: #b91c1c;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _choose(self, action):
|
|
||||||
if self._completed:
|
if self._completed:
|
||||||
return
|
return
|
||||||
self._completed = True
|
self._completed = True
|
||||||
self.action_selected.emit(action)
|
self.action_selected.emit(accepted)
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
if not self._completed:
|
if not self._completed:
|
||||||
self._completed = True
|
self._completed = True
|
||||||
self.action_selected.emit('cancel')
|
self.action_selected.emit(False)
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ from core.controllers.tickets.UseTicketController import (
|
||||||
)
|
)
|
||||||
from core.models.session.SessionProfile import SessionProfile
|
from core.models.session.SessionProfile import SessionProfile
|
||||||
from core.models.system.SystemProfile import SystemProfile
|
from core.models.system.SystemProfile import SystemProfile
|
||||||
from core.models.Result import ResultError
|
from core.models.Result import Result, ResultError
|
||||||
from core.errors.exceptions import SudoScript, MissingPreReqs, FirewallError
|
from core.errors.exceptions import SudoScript, MissingPreReqs, FirewallError
|
||||||
from core.Errors import (
|
from core.Errors import (
|
||||||
CommandNotFoundError,
|
CommandNotFoundError,
|
||||||
|
|
@ -25,11 +25,7 @@ from core.Errors import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from gui.v2.actions.database_health import GuiStorageDatabaseError
|
from gui.v2.actions.database_health import GuiStorageDatabaseError
|
||||||
from gui.v2.actions.operation_results import (
|
from gui.v2.actions.operation_results import result_from_exception
|
||||||
operation_failure_payload,
|
|
||||||
result_data,
|
|
||||||
result_is_valid,
|
|
||||||
)
|
|
||||||
from gui.v2.infrastructure.screen_size import get_max_screensize
|
from gui.v2.infrastructure.screen_size import get_max_screensize
|
||||||
from gui.v2.infrastructure.setup_observers import (
|
from gui.v2.infrastructure.setup_observers import (
|
||||||
application_version_observer,
|
application_version_observer,
|
||||||
|
|
@ -114,9 +110,12 @@ class Worker(QObject):
|
||||||
ignore_exceptions.append(ProfileStateConflictError)
|
ignore_exceptions.append(ProfileStateConflictError)
|
||||||
ignore_tuple = tuple(ignore_exceptions)
|
ignore_tuple = tuple(ignore_exceptions)
|
||||||
max_resolution = get_max_screensize()
|
max_resolution = get_max_screensize()
|
||||||
ProfileController.enable(self.profile, ignore=ignore_tuple, profile_observer=profile_observer,
|
enable_result = ProfileController.enable(self.profile, ignore=ignore_tuple, profile_observer=profile_observer,
|
||||||
application_version_observer=application_version_observer,
|
application_version_observer=application_version_observer,
|
||||||
connection_observer=connection_observer, ticket_observer=ticket_observer, max_resolution=max_resolution)
|
connection_observer=connection_observer, ticket_observer=ticket_observer, max_resolution=max_resolution)
|
||||||
|
if isinstance(enable_result, Result) and not enable_result.valid:
|
||||||
|
self.operation_failed.emit(enable_result)
|
||||||
|
return
|
||||||
except EndpointVerificationError:
|
except EndpointVerificationError:
|
||||||
self.update_signal.emit(
|
self.update_signal.emit(
|
||||||
"ENDPOINT_VERIFICATION_ERROR", False, self.profile_data['id'], None, None)
|
"ENDPOINT_VERIFICATION_ERROR", False, self.profile_data['id'], None, None)
|
||||||
|
|
@ -213,11 +212,11 @@ class Worker(QObject):
|
||||||
if error_msg:
|
if error_msg:
|
||||||
self._emit_ticket_failure(
|
self._emit_ticket_failure(
|
||||||
None,
|
None,
|
||||||
result={
|
result=Result(
|
||||||
'valid': False,
|
valid=False,
|
||||||
'error_type': ResultError.TICKET,
|
error_type=ResultError.TICKET,
|
||||||
'message': f'Ticket use failed: {error_msg}',
|
message=f'Ticket use failed: {error_msg}',
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
if which_ticket is None or which_ticket == 'error':
|
if which_ticket is None or which_ticket == 'error':
|
||||||
|
|
@ -238,29 +237,17 @@ class Worker(QObject):
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _retry_profile_data(self, which_ticket=None):
|
|
||||||
profile_data = dict(self.profile_data)
|
|
||||||
profile_data.pop('billing_code', None)
|
|
||||||
if which_ticket is not None:
|
|
||||||
profile_data['use_ticket'] = which_ticket
|
|
||||||
return profile_data
|
|
||||||
|
|
||||||
def _emit_ticket_failure(self, which_ticket, result=None, message=None, exception=None):
|
def _emit_ticket_failure(self, which_ticket, result=None, message=None, exception=None):
|
||||||
self._ticket_error_emitted = True
|
self._ticket_error_emitted = True
|
||||||
context = {
|
if exception is not None:
|
||||||
'profile_data': self._retry_profile_data(which_ticket),
|
result = result_from_exception(exception)
|
||||||
}
|
elif result is None:
|
||||||
if which_ticket is not None:
|
result = Result(
|
||||||
context['ticket'] = str(which_ticket)
|
valid=False,
|
||||||
self.operation_failed.emit(
|
error_type=ResultError.UNKNOWN,
|
||||||
operation_failure_payload(
|
message=message or 'Ticket use failed.',
|
||||||
operation='use_ticket',
|
|
||||||
result=result,
|
|
||||||
message=message,
|
|
||||||
exception=exception,
|
|
||||||
context=context,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
self.operation_failed.emit(result)
|
||||||
|
|
||||||
def _emit_subscription_lookup_failure(self, exception=None):
|
def _emit_subscription_lookup_failure(self, exception=None):
|
||||||
message = (
|
message = (
|
||||||
|
|
@ -273,11 +260,11 @@ class Worker(QObject):
|
||||||
message = f"{message} {error_text}"
|
message = f"{message} {error_text}"
|
||||||
self._emit_ticket_failure(
|
self._emit_ticket_failure(
|
||||||
self._consumed_ticket,
|
self._consumed_ticket,
|
||||||
result={
|
result=Result(
|
||||||
'valid': False,
|
valid=False,
|
||||||
'error_type': ResultError.CONNECTION,
|
error_type=ResultError.CONNECTION,
|
||||||
'message': message,
|
message=message,
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def _consume_ticket(self, which_ticket):
|
def _consume_ticket(self, which_ticket):
|
||||||
|
|
@ -285,11 +272,11 @@ class Worker(QObject):
|
||||||
if which_location is None:
|
if which_location is None:
|
||||||
self._emit_ticket_failure(
|
self._emit_ticket_failure(
|
||||||
which_ticket,
|
which_ticket,
|
||||||
result={
|
result=Result(
|
||||||
'valid': False,
|
valid=False,
|
||||||
'error_type': ResultError.MISSING_DATA,
|
error_type=ResultError.MISSING_DATA,
|
||||||
'message': 'Could not determine profile location for ticket use.',
|
message='Could not determine profile location for ticket use.',
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -305,16 +292,27 @@ class Worker(QObject):
|
||||||
self._emit_ticket_failure(which_ticket, exception=e)
|
self._emit_ticket_failure(which_ticket, exception=e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if result_is_valid(outcome):
|
if not isinstance(outcome, Result):
|
||||||
billing_code = result_data(outcome)
|
self._emit_ticket_failure(
|
||||||
|
which_ticket,
|
||||||
|
result=Result(
|
||||||
|
valid=False,
|
||||||
|
error_type=ResultError.INVALID_API_REPLY,
|
||||||
|
message=f'use_ticket returned {type(outcome).__name__}, expected Result.',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
if outcome.valid:
|
||||||
|
billing_code = outcome.data
|
||||||
if not billing_code:
|
if not billing_code:
|
||||||
self._emit_ticket_failure(
|
self._emit_ticket_failure(
|
||||||
which_ticket,
|
which_ticket,
|
||||||
result={
|
result=Result(
|
||||||
'valid': False,
|
valid=False,
|
||||||
'error_type': ResultError.INVALID_API_REPLY,
|
error_type=ResultError.INVALID_API_REPLY,
|
||||||
'message': 'Ticket use succeeded but no billing code was returned.',
|
message='Ticket use succeeded but no billing code was returned.',
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
self._consumed_ticket = str(which_ticket)
|
self._consumed_ticket = str(which_ticket)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue