Isolated Error translation to core repo. Slightly changed ticket flow

This commit is contained in:
SimplifiedPrivacy 2026-10-17 17:12:22 -04:00
parent 9cb3d607b4
commit de19732055
2 changed files with 25 additions and 134 deletions

View file

@ -4,17 +4,13 @@ from core.services.prepare_tickets.ticket_tracker import get_a_random_ticket
from core.services.profiles.profile_connections import enable_profile #, disable_profile from core.services.profiles.profile_connections import enable_profile #, disable_profile
from core.controllers.ProfileController import ProfileController from core.controllers.ProfileController import ProfileController
from core.models.Configuration import Configuration, ConnectionChoice from core.models.Configuration import Configuration, ConnectionChoice
from core.services.subscriptions.subscriptions_by_protocol import get_profile_subscription, start_new_payment_cycle, wipe_subscription, wipe_billing_cycle from core.services.subscriptions.subscriptions_by_protocol import get_profile_subscription, start_new_payment_cycle, wipe_subscription
from core.utils.check_if_time_lapsed import check_if_time_lapsed from core.utils.check_if_time_lapsed import check_if_time_lapsed
from core.models.enum_models import PaymentCategory from core.models.enum_models import PaymentCategory
from core.utils.type_checker import type_checker from core.utils.type_checker import type_checker
from core.models.Result import Result, ResultError from core.models.Result import Result, ResultError
from core.errors.logger import logger from core.errors.logger import logger
from core.Errors import ( from core.errors.translate_error import translate_error, get_ignored_exceptions
CommandNotFoundError, EndpointVerificationError, FileIntegrityError,
InvalidSubscriptionError, MissingSubscriptionError, ProfileActivationError,
ProfileModificationError, ProfileStateConflictError, UnsupportedApplicationVersionError,
)
# gui # gui
from gui.v2.actions.ticket_actions import get_ticket_data, use_a_ticket from gui.v2.actions.ticket_actions import get_ticket_data, use_a_ticket
@ -26,17 +22,8 @@ from gui.v2.infrastructure.setup_observers import (
profile_observer, ticket_observer, profile_observer, ticket_observer,
) )
# generic # generic
from typing import Callable, Optional, Type from typing import Callable, Optional
ERROR_TO_UI_MESSAGE = {
ProfileActivationError: "The profile could not be enabled",
UnsupportedApplicationVersionError: "The application version in question is not supported",
FileIntegrityError: "Application version file integrity could not be verified.",
ProfileModificationError: "WireGuard configuration could not be attached.",
}
def get_profile(profile_id: int): def get_profile(profile_id: int):
@ -47,21 +34,6 @@ def get_profile(profile_id: int):
return Result(valid=True, data=profile) return Result(valid=True, data=profile)
def get_ignored_exceptions(ignore_state_conflict: Optional[bool] = False):
ignored_as_list = []
config = Configuration.get()
endpoint_verification_enabled = config.endpoint_verification_enabled
if endpoint_verification_enabled:
ignored_as_list.append(EndpointVerificationError)
if ignore_state_conflict:
ignored_as_list.append(ProfileStateConflictError)
ignored = tuple(ignored_as_list)
return ignored
@register_action(ResultError.SUBSCRIPTION) @register_action(ResultError.SUBSCRIPTION)
def navigate_to_new_sub_page() -> Result: def navigate_to_new_sub_page() -> Result:
return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="id", message="No subscription. Pick a payment method.") return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="id", message="No subscription. Pick a payment method.")
@ -89,6 +61,7 @@ def start_and_navigate_to_ticketing():
return start_result return start_result
def random_ticket_dispatch(profile_id: int, passed_ui_caller: Callable) -> Result: def random_ticket_dispatch(profile_id: int, passed_ui_caller: Callable) -> Result:
""" """
User explicitly wants a random ticket. User explicitly wants a random ticket.
@ -113,7 +86,7 @@ def random_ticket_dispatch(profile_id: int, passed_ui_caller: Callable) -> Resul
def dispatch_ticketing(profile_id: int, passed_ui_caller: Callable) -> Result: def dispatch_ticketing(profile_id: int, passed_ui_caller: Callable) -> Result:
"""Evaluate if a random ticket will be used.""" """Evaluate if a random ticket will be used."""
use_random_setting = ConfigurationController.use_random use_random_setting = ConfigurationController.use_random()
if use_random_setting: if use_random_setting:
return random_ticket_dispatch(profile_id=profile_id, passed_ui_caller=passed_ui_caller) return random_ticket_dispatch(profile_id=profile_id, passed_ui_caller=passed_ui_caller)
@ -125,7 +98,7 @@ def dispatch_ticketing(profile_id: int, passed_ui_caller: Callable) -> Result:
return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="ticket_or_billing_choice") return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="ticket_or_billing_choice")
else: else:
# user can pick between tickets or individual: # user can decide if they want to setup tickets or do an individual profile:
return navigate_to_new_sub_page() return navigate_to_new_sub_page()
@ -178,12 +151,9 @@ def filter_subscription(profile_id: int, passed_ui_caller: Callable) -> Result:
return Result(valid=True) return Result(valid=True)
@register_action(ResultError.TOR_NEEDED) @register_action(ResultError.TOR_NEEDED)
def switch_to_tor_connection() -> Result: def switch_to_tor_connection() -> Result:
config = Configuration.get() ConfigurationController.set_connection_enum(ConnectionChoice.TOR)
config.connection = ConnectionChoice.TOR
config.save()
return Result(valid=True) return Result(valid=True)
@ -221,6 +191,7 @@ def NOT_need_tor_warnings(profile_id: int) -> Result:
return Result(valid=False, error_type=ResultError.TOR_NEEDED, message=error_msg) return Result(valid=False, error_type=ResultError.TOR_NEEDED, message=error_msg)
@register_action(ResultError.ENDPOINT_VERIFICATION) @register_action(ResultError.ENDPOINT_VERIFICATION)
def literally_connect( def literally_connect(
profile_id: int, profile_id: int,
@ -255,78 +226,32 @@ def literally_connect(
else: else:
return Result(valid=True) return Result(valid=True)
except Exception as error: except Exception as error:
return enable_error(error=error, profile_id=profile_id) return translate_error(error=error, profile_id=profile_id)
def enable_error(error: Type[Exception], profile_id: int) -> Result:
"""Translate core errors into actions and/or messages via Result Objects."""
logger.error(str(error))
#---------------------- @register_action(ResultError.STATE_CONFLICT)
# PURE MESSAGES (NO SOLUTION FUNCTION) def ignore_state_conflict(profile_id: int) -> Result:
#---------------------- return literally_connect(
if error in ERROR_TO_UI_MESSAGE:
error_msg = ERROR_TO_UI_MESSAGE[error]
return Result(valid=False, error_type=ResultError.UNKNOWN, message=error_msg)
#----------------------
# ENDPOINT VERIFICATION
#----------------------
if isinstance(error, EndpointVerificationError):
return Result(valid=False, error_type=ResultError.ENDPOINT_VERIFICATION, message="Operator verification failed. Do you want to continue anyway?")
#----------------------
# STATE CONFLICT
#----------------------
if isinstance(error, ProfileStateConflictError):
function_choice = literally_connect(
profile_id=profile_id, profile_id=profile_id,
ignore_state_conflict=True ignore_state_conflict=True
) )
error_msg = "The profile is already enabled. Do you want to force enable it anyway?"
return Result(valid=False, function_choice=function_choice, error_type=ResultError.STATE_CONFLICT, message=error_msg)
#----------------------
# SUBSCRIPTION
#----------------------
if isinstance(error, (InvalidSubscriptionError, MissingSubscriptionError)):
error_msg = f"Subscription missing or invalid for profile {profile_id}. Do you want to get a new sub?"
return Result(valid=False, error_type=ResultError.SUBSCRIPTION, message=error_msg)
#----------------------
# COMMAND NOT FOUND
#----------------------
if isinstance(error, CommandNotFoundError):
# add install later!!
name_of_package = str(error.subject)
error_msg = f"You're missing the {name_of_package} package. Please install it."
return Result(valid=False, error_type=ResultError.MISSING_SOFTWARE, message=error_msg)
else:
return Result(valid=False, error_type=ResultError.UNKNOWN, message="An unknown error occured.")
def _connect_profile(profile_id: int, passed_ui_caller: Callable) -> Result: def _connect_profile(profile_id: int, passed_ui_caller: Callable) -> Result:
"""Background Threaded Orchestration to Start a Connection""" """Background Threaded Orchestration to Start a Connection"""
# # Step 1: Get the Profile # Step 1: Subscription filter:
# profile_result = get_profile(profile_id)
# if not profile_result:
# return Result(valid=False, error_type=ResultError.INVALID_INPUT, message="This profile does not match one of your configuration files.")
# profile = profile_result.data
# Step 2: Subscription filter:
sub_result = filter_subscription(profile_id=profile_id, passed_ui_caller=passed_ui_caller) sub_result = filter_subscription(profile_id=profile_id, passed_ui_caller=passed_ui_caller)
if not sub_result.valid: if not sub_result.valid:
return sub_result return sub_result
# Step 3: Tor filter check: # Step 2: Tor filter check:
result = NOT_need_tor_warnings(profile_id=profile_id) result = NOT_need_tor_warnings(profile_id=profile_id)
if not result.valid: if not result.valid:
return result return result
# Actual Connection: # Step 3: Actual Connection:
logger.info(f"Profile id {profile_id} is ready to connect..") logger.info(f"Profile id {profile_id} is ready to connect..")
return literally_connect(profile_id=profile_id) return literally_connect(profile_id=profile_id)
@ -343,3 +268,4 @@ def connect_profile(profile_id: int, ui_caller: Callable) -> Result:
return Result(valid=True) return Result(valid=True)

View file

@ -35,46 +35,6 @@ def fetch_ticket_invoice(ui_caller: Callable) -> str | None:
) )
# def fetch_ticket_invoice(invoice_ui_caller: Callable, timer_resume_caller: Callable) -> str | None:
# """Start the Ticketing process on the background thread with the relevant billing data."""
# logger.info("fetching ticket invoice..")
# payment_cycle = OverallPaymentCycle()
# if not payment_cycle:
# "No payment cycle, and therefore no data."
# # already existing but wrong format:
# if payment_cycle.category != PaymentCategory.TICKET:
# return "Wrong payment cycle category."
# billing_data = payment_cycle.instance
# if not billing_data:
# return "No billing data"
# # if not isinstance(billing_data, TicketPaymentData):
# # return "Billing data in the wrong format."
# which_key = billing_data.which_key
# currency = billing_data.currency
# how_many_profiles = billing_data.how_many_profiles
# # Fetch (this function will complain if missing data):
# take_action(
# action=initiate_payment,
# ui_caller=invoice_ui_caller,
# how_many_profiles=how_many_profiles,
# which_key=which_key,
# which_cryptocurrency=currency,
# ticket_observer=ticket_observer,
# connection_observer=connection_observer,
# bypass_existing=True,
# )
# logger.info("Initiated payment")
def get_ticket_data() -> Result: def get_ticket_data() -> Result:
"""This is running in the background ALREADY. Get & format a list of unused tickets from core""" """This is running in the background ALREADY. Get & format a list of unused tickets from core"""
@ -160,3 +120,8 @@ class TicketUser():
logger.info("Saved sub, returning to UI layer..") logger.info("Saved sub, returning to UI layer..")
self.ui_caller(result) self.ui_caller(result)
def wipe_ticket_billing():
"""Wipe existing data and start over."""