diff --git a/gui/v2/actions/profile_operations.py b/gui/v2/actions/profile_operations.py index 06f1b70..e3340c9 100755 --- a/gui/v2/actions/profile_operations.py +++ b/gui/v2/actions/profile_operations.py @@ -200,9 +200,9 @@ def _enable(request: dict[str, Any], emit: MenuCallback, max_resolution: str | N print(f"checking preparation") - # preparation = _prepare_subscription(profile, request) - # if preparation is not None: - # return preparation + preparation = _prepare_subscription(profile, request) + if preparation is not None: + return preparation print("entering observers") ignored = {"ignore_endpoint_verification": EndpointVerificationError, diff --git a/gui/v2/actions/ticket_actions.py b/gui/v2/actions/ticket_actions.py index 6d9612e..261ec5c 100644 --- a/gui/v2/actions/ticket_actions.py +++ b/gui/v2/actions/ticket_actions.py @@ -1,24 +1,23 @@ # core +from core.controllers.tickets.UseTicketController import use_ticket +from core.models.BaseProfile import BaseProfile as Profile +from core.controllers.ProfileController import ProfileController from core.controllers.tickets.TicketPayController import initiate_payment -from core.services.subscriptions.subscriptions_by_protocol import start_billing_state -from core.services.payment_phase.payment_state import OverallPaymentCycle, TicketPaymentData -from core.models.enum_models import PaymentType, PaymentCategory -# from core.controllers.tickets.UseTicketController import get_unused_tickets +from core.services.subscriptions.subscriptions_by_protocol import start_billing_state, save_subscription +from core.services.payment_phase.payment_state import OverallPaymentCycle +from core.models.enum_models import PaymentCategory from core.services.prepare_tickets.ticket_tracker import get_all_unused_tickets - from core.models.Result import Result, ResultError -# from core.controllers.ProfileController import ProfileController from core.errors.logger import logger # gui -from gui.v2.infrastructure.ThreadSafetyTool import ThreadSafetyTool from gui.v2.infrastructure.take_plumbing_action import take_action from gui.v2.infrastructure.setup_observers import connection_observer, ticket_observer +# generic: from typing import Callable - def start_ticket(ui_caller: Callable) -> Result: logger.info("started ticketing billing state") return take_action( @@ -87,4 +86,69 @@ def get_ticket_data() -> Result: formatted_data = [(f"Ticket #{t}", t) for t in raw_tickets] print(f"formatted_data is {formatted_data}") - return Result(valid=True, data=formatted_data) \ No newline at end of file + return Result(valid=True, data=formatted_data) + + +def use_a_ticket(profile_id: int, which_ticket: int, ui_caller: Callable) -> str | None: + """Coordinate the use of a given ticket. Returns a string on error, or None on success""" + + try: + profile = ProfileController.get(int(profile_id)) + except Exception as e: + return f"The selected profile of {str(profile_id)} is either malformed or missing. {str(e)}" + + which_location = profile.location.id + protocol_choice = profile.connection.code + + PRE_REQS = [profile, which_ticket, which_location, protocol_choice, ui_caller] + if None in PRE_REQS: + return "You are missing one of the pre-reqs to use a ticket." + + ticket_user = TicketUser( + actual_profile=profile, + which_ticket=which_ticket, + ui_caller=ui_caller + ) + ticket_user.begin_thread() + return None # no error + + +class TicketUser(): + actual_profile: Profile + which_ticket: int + ui_caller: Callable + + def begin_thread(self): + """Step 1, begin a background thread with use""" + take_action( + action=use_ticket, + ui_caller=self.apply_code, + which_location=self.which_location, + protocol_choice=self.protocol_choice, + ticket_observer=ticket_observer, + connection_observer=connection_observer, + ) + + def apply_code(self, result: Result): + """Step 2. Check if it worked. If so, apply it""" + + if not result.valid: + logger.error("Use failed, returning to UI layer..") + self.ui_caller(result) + + subscription = result.data + if not subscription: + logger.error("Use of ticket gave a blank subscription, returning to UI layer..") + self.ui_caller(result) + + # core saves it: + logger.info("saving subscription..") + saved = save_subscription(profile=self.actual_profile, subscription=subscription) + if not saved: + error_msg = "Could not save the subscription" + logger.error(error_msg) + new_result = Result(valid=False, error_type=ResultError.FILE_SYSTEM, message=error_msg) + self.ui_caller(new_result) + + logger.info("Saved sub, returning to UI layer..") + self.ui_caller(result) \ No newline at end of file diff --git a/gui/v2/ui/pages/ticket_or_billing_choice_page.py b/gui/v2/ui/pages/ticket_or_billing_choice_page.py index 4f1b55e..5db6c57 100755 --- a/gui/v2/ui/pages/ticket_or_billing_choice_page.py +++ b/gui/v2/ui/pages/ticket_or_billing_choice_page.py @@ -1,5 +1,4 @@ # core -# from core.controllers.ProfileController import ProfileController # from core.controllers.tickets.UseTicketController import get_unused_tickets from core.models.Result import Result, ResultError @@ -122,41 +121,62 @@ class TicketOrBillingChoicePage(Page): profile_id = int(self.update_status.current_profile_id) print(f"profile_id is {profile_id}") + if not profile_id: + self.update_status.update_status("Can not find the correct profile id") + return + + error_msg = use_a_ticket(profile_id=profile_id, which_ticket=which_ticket, ui_caller=self.recieve_use_result) + if error_msg: + self.show_a_popup(str(error_msg)) + else: + self.update_status.update_status(f"Using ticket #{which_ticket}...") - # def on_use_ticket(self): - # item = self.ticket_list.currentItem() - # if not item: - # self.status_label.setText("Pick a ticket from the list first.") - # return - # which_ticket = item.data(QtCore.Qt.ItemDataRole.UserRole) + def recieve_use_result(self, result: Result): + """Recieves the callback from gui_uses_ticket""" + if not result: + self.show_a_popup("This is a developer error, the use of the ticket failed to produce a result object") + if not result.valid: + self.update_status.update_status(str(result.message)) + return - # profile_id = self.update_status.current_profile_id - # try: - # profile = ProfileController.get(int(profile_id)) - # except Exception: - # profile = None - # candidates = location_candidates(profile) - # if not candidates: - # self.status_label.setText("Could not determine profile location.") - # return - # profile_data = { - # 'id': int(profile_id), - # 'use_ticket': which_ticket, - # 'ticket_location': candidates[0] - # } - # menu_page = self.custom_window.navigator.get_cached("menu") - # if menu_page: - # self.update_status.update_status(f"Using ticket #{which_ticket}...") - # self.profile_enable_worker = enable_profile( - # profile_data, menu_page.handle_task_result, allow_uninstalled_tor=True, - # ) - # self.custom_window.navigator.navigate("menu") + menu_page = self.custom_window.navigator.get_cached("menu") + if menu_page: + self.update_status.update_status("Ticket Use Worked!") + self.custom_window.navigator.navigate("menu") def on_use_billing(self): self.custom_window.navigator.navigate("id") def reverse(self): self.custom_window.navigator.navigate("menu") + + + +# def on_use_ticket(self): +# item = self.ticket_list.currentItem() +# if not item: +# self.status_label.setText("Pick a ticket from the list first.") +# return +# which_ticket = item.data(QtCore.Qt.ItemDataRole.UserRole) + +# profile_id = self.update_status.current_profile_id +# try: +# profile = ProfileController.get(int(profile_id)) +# except Exception: +# profile = None +# candidates = location_candidates(profile) +# if not candidates: +# self.status_label.setText("Could not determine profile location.") +# return +# profile_data = { +# 'id': int(profile_id), +# 'use_ticket': which_ticket, +# 'ticket_location': candidates[0] +# } + +# self.profile_enable_worker = enable_profile( +# profile_data, menu_page.handle_task_result, allow_uninstalled_tor=True, +# )