When a profile is deleted, it now automatically respawns the ticket if it's a ticket profile. Also fixed some bugs with fetching the server's public key with the APIResponse object being used, when it expected a regular dictionary. This is a left-over from the prior transition to API objects.
This commit is contained in:
parent
829feb5939
commit
5ab57ab287
7 changed files with 96 additions and 13 deletions
|
|
@ -1,5 +1,10 @@
|
||||||
# Major Change Log:
|
# Major Change Log:
|
||||||
|
|
||||||
|
# Respawn on Delete
|
||||||
|
### Aug 15, 2026
|
||||||
|
When a profile is deleted, it now automatically respawns the ticket if it's a ticket profile. Also fixed some bugs with fetching the server's public key with the APIResponse object being used, when it expected a regular dictionary. This is a left-over from the prior transition to API objects.
|
||||||
|
<br/>
|
||||||
|
|
||||||
# Codes/Tickets
|
# Codes/Tickets
|
||||||
### Aug 15, 2026
|
### Aug 15, 2026
|
||||||
The profile object now has a ticket field. It's now none by default. Also the profile object is passed in, for the use of tickets, both for GUI and core.
|
The profile object now has a ticket field. It's now none by default. Also the profile object is passed in, for the use of tickets, both for GUI and core.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,10 @@ from core.services.networking.systemwide import killswitch
|
||||||
from core.services.subscriptions import subscriptions
|
from core.services.subscriptions import subscriptions
|
||||||
from core.errors.exceptions import FirewallError
|
from core.errors.exceptions import FirewallError
|
||||||
from core.models.Result import Result, ResultError
|
from core.models.Result import Result, ResultError
|
||||||
|
from core.observers.TicketObserver import TicketObserver
|
||||||
|
from core.controllers.tickets.TicketPrepController import respawn_billing_code_into_ticket
|
||||||
|
from core.services.prepare_tickets.ticket_tracker import get_tickets_with
|
||||||
|
from core.errors.logger import logger
|
||||||
|
|
||||||
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError
|
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError
|
||||||
from core.controllers.ApplicationController import ApplicationController
|
from core.controllers.ApplicationController import ApplicationController
|
||||||
|
|
@ -182,8 +186,47 @@ class ProfileController:
|
||||||
time.sleep(1.0)
|
time.sleep(1.0)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def destroy(profile: Union[SessionProfile, SystemProfile], profile_observer: ProfileObserver = None):
|
def destroy(profile: Union[SessionProfile, SystemProfile], profile_observer: ProfileObserver = None, ticket_observer: TicketObserver = None, connection_observer: ConnectionObserver = None):
|
||||||
|
|
||||||
|
####################################
|
||||||
|
# DESTROY TICKET
|
||||||
|
####################################
|
||||||
|
which_ticket = profile.ticket
|
||||||
|
|
||||||
|
# try via lookup:
|
||||||
|
if not which_ticket:
|
||||||
|
logger.info(f"Unable to find the ticket # in the profile's native config for {profile.id}. Checking the ticket tracker JSON")
|
||||||
|
target_subscription = profile.subscription.billing_code
|
||||||
|
ticket_list = get_tickets_with(target_subscription)
|
||||||
|
if len(ticket_list) >= 1:
|
||||||
|
which_ticket = ticket_list[0]
|
||||||
|
logger.info(f"We got the ticket {which_ticket} for profile {profile.id} from the ticket tracker JSON")
|
||||||
|
else:
|
||||||
|
logger.info(f"We were UNABLE to find a ticket with the subscription for profile {profile.id} from the ticket tracker JSON. Proceeding with delete regardless..")
|
||||||
|
|
||||||
|
# Regardless of how it was acquired,
|
||||||
|
if which_ticket:
|
||||||
|
notification = f"Respawn Started for Ticket {which_ticket}"
|
||||||
|
logger.info(notification)
|
||||||
|
ticket_observer.notify("preparing", subject=notification)
|
||||||
|
respawn_result = respawn_billing_code_into_ticket(
|
||||||
|
profile=profile,
|
||||||
|
which_ticket=which_ticket,
|
||||||
|
ticket_observer=ticket_observer,
|
||||||
|
connection_observer=connection_observer
|
||||||
|
)
|
||||||
|
if respawn_result.valid:
|
||||||
|
notification = f"Ticket Respawned!"
|
||||||
|
logger.info(notification)
|
||||||
|
ticket_observer.notify("preparing", subject=notification)
|
||||||
|
else:
|
||||||
|
notification = f"Error with Ticket Respawn!"
|
||||||
|
logger.error(f"{notification} {respawn_result.error_type} with message: {respawn_result.message}")
|
||||||
|
ticket_observer.notify("preparing", subject=notification)
|
||||||
|
|
||||||
|
####################################
|
||||||
|
# DESTROY PROFILE
|
||||||
|
####################################
|
||||||
ProfileController.disable(profile)
|
ProfileController.disable(profile)
|
||||||
profile.delete()
|
profile.delete()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ def respawn_billing_code_into_ticket(
|
||||||
which_ticket: int,
|
which_ticket: int,
|
||||||
ticket_observer: TicketObserver,
|
ticket_observer: TicketObserver,
|
||||||
connection_observer: ConnectionObserver
|
connection_observer: ConnectionObserver
|
||||||
) -> bool:
|
) -> Result:
|
||||||
"""
|
"""
|
||||||
Converts a valid VPN billing code, into a valid unused ticket.
|
Converts a valid VPN billing code, into a valid unused ticket.
|
||||||
At the cost of the server expiring the billing code immediately.
|
At the cost of the server expiring the billing code immediately.
|
||||||
|
|
@ -128,7 +128,10 @@ def respawn_billing_code_into_ticket(
|
||||||
return Result(valid=False, error_type=ResultError.MISSING_DATA, message="Missing which ticket slot is being respawned")
|
return Result(valid=False, error_type=ResultError.MISSING_DATA, message="Missing which ticket slot is being respawned")
|
||||||
|
|
||||||
if not isinstance(which_ticket, int):
|
if not isinstance(which_ticket, int):
|
||||||
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message="Ticket slot must be a number.")
|
try:
|
||||||
|
which_ticket = int(which_ticket)
|
||||||
|
except:
|
||||||
|
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message="Ticket slot must be a number.")
|
||||||
|
|
||||||
ticket_result = prepare_tickets(
|
ticket_result = prepare_tickets(
|
||||||
how_many_profiles=1,
|
how_many_profiles=1,
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ def get_from_server_and_save(
|
||||||
|
|
||||||
url = make_url(string_form_of_key_name)
|
url = make_url(string_form_of_key_name)
|
||||||
|
|
||||||
# public_key_results = get_data_from_server(url, connection_observer)
|
|
||||||
public_key_results = connect.single_endpoint(
|
public_key_results = connect.single_endpoint(
|
||||||
method="get",
|
method="get",
|
||||||
url=url,
|
url=url,
|
||||||
|
|
@ -39,14 +38,22 @@ def get_from_server_and_save(
|
||||||
payload=None
|
payload=None
|
||||||
)
|
)
|
||||||
|
|
||||||
if public_key_results.valid:
|
if not public_key_results.valid:
|
||||||
# extract:
|
error_msg = f"Error with API getting the Public Key: {public_key_results.error_type} and {public_key_results.message}"
|
||||||
public_key = public_key_results.data
|
logger.error(error_msg)
|
||||||
|
return {"valid": False, "message": error_msg}
|
||||||
|
|
||||||
# save it:
|
# extract:
|
||||||
did_it_save = write_string_to_text_file(public_key, file_path)
|
public_key = public_key_results.data
|
||||||
|
|
||||||
return public_key_results
|
# save it:
|
||||||
|
did_it_save = write_string_to_text_file(public_key, file_path)
|
||||||
|
|
||||||
|
if not did_it_save:
|
||||||
|
logger.error(f"Error with saving the public key {public_key} with write_string_to_text_file, but still returning data..")
|
||||||
|
|
||||||
|
# regardless of saving:
|
||||||
|
return {"valid": True, "data": public_key}
|
||||||
|
|
||||||
|
|
||||||
def get_pub_key(
|
def get_pub_key(
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ from core.services.helpers.get_which_billing_key import get_which_billing_key
|
||||||
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.Subscription import Subscription # not sure if needed
|
from core.models.Subscription import Subscription # not sure if needed
|
||||||
from core.controllers.ProfileController import ProfileController
|
# from core.controllers.ProfileController import ProfileController
|
||||||
|
|
||||||
# utils
|
# utils
|
||||||
from core.utils.basic_operations.write_or_read_from_json import get_value_from_json_file
|
from core.utils.basic_operations.write_or_read_from_json import get_value_from_json_file
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
from core.utils.basic_operations.write_or_read_from_json import read_entire_json, update_json
|
from core.utils.basic_operations.write_or_read_from_json import read_entire_json, update_json
|
||||||
|
from core.utils.basic_operations.does_file_exist import does_file_exist
|
||||||
from core.errors.exceptions import *
|
from core.errors.exceptions import *
|
||||||
from core.errors.logger import logger
|
from core.errors.logger import logger
|
||||||
from core.Constants import Constants
|
from core.Constants import Constants
|
||||||
|
|
||||||
|
# generic
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
@ -88,4 +90,23 @@ def wipe_one_ticket_sub(which_ticket: int) -> bool:
|
||||||
filepath=Constants.TICKET_TRACKER_PATH,
|
filepath=Constants.TICKET_TRACKER_PATH,
|
||||||
key_to_add=which_ticket,
|
key_to_add=which_ticket,
|
||||||
value_to_update=wipe_payload
|
value_to_update=wipe_payload
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_tickets_with(target_subscription: str) -> list:
|
||||||
|
|
||||||
|
if not does_file_exist(Constants.TICKET_TRACKER_PATH):
|
||||||
|
return []
|
||||||
|
|
||||||
|
whole_json = read_entire_json(Constants.TICKET_TRACKER_PATH)
|
||||||
|
if not whole_json:
|
||||||
|
return []
|
||||||
|
|
||||||
|
list_of_matches = []
|
||||||
|
|
||||||
|
for each_number in whole_json:
|
||||||
|
if whole_json[each_number]['subscription'] == target_subscription:
|
||||||
|
list_of_matches.append(each_number)
|
||||||
|
|
||||||
|
return list_of_matches
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import os
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Note: this function will accept EITHER raw dicts or string, WITHOUT converting to JSON,
|
Note: this function will accept EITHER raw dicts or string, WITHOUT converting to JSON,
|
||||||
and literally convert to str to save. At a first glance, this seems ridiculous.
|
and literally convert to str to save. At a first glance, this seems ridiculous.
|
||||||
|
|
@ -13,16 +15,18 @@ Therefore, we opted for this data storage format for some data types.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def write_string_to_text_file(content_to_write: str | dict, file_path: str) -> bool:
|
def write_string_to_text_file(content_to_write: str | dict, file_path: str) -> bool:
|
||||||
if content_to_write is None:
|
if content_to_write is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||||
with open(file_path, "w") as file:
|
with open(file_path, "w") as file:
|
||||||
file.write(str(content_to_write))
|
file.write(str(content_to_write))
|
||||||
return True
|
return True
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(f"Error: The file '{file_path}' was not found.")
|
print(f"Error inside of write_string_to_text: The file '{file_path}' was not found.")
|
||||||
return False
|
return False
|
||||||
except IOError:
|
except IOError:
|
||||||
print(
|
print(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue