Resume Payments for individual profiles stable. Also fixed a bug with errors in filtering invalid replies to getting new wireguard conifgs
This commit is contained in:
parent
52b3e1ba94
commit
430696b480
5 changed files with 96 additions and 50 deletions
|
|
@ -14,10 +14,12 @@ TRANSLATION_DICT = {
|
||||||
ServerError.INVALID: ResultError.INVALID_INPUT,
|
ServerError.INVALID: ResultError.INVALID_INPUT,
|
||||||
ServerError.MISSING_DATA: ResultError.INVALID_INPUT,
|
ServerError.MISSING_DATA: ResultError.INVALID_INPUT,
|
||||||
ServerError.UNPAID: ResultError.SUBSCRIPTION,
|
ServerError.UNPAID: ResultError.SUBSCRIPTION,
|
||||||
ServerError.SERVER_SIDE: ResultError.SERVER_SIDE
|
ServerError.SERVER_SIDE: ResultError.SERVER_SIDE,
|
||||||
|
ServerError.EXPIRED: ResultError.SUBSCRIPTION
|
||||||
}
|
}
|
||||||
|
|
||||||
def format_server_response(api_response: ApiResponse, desired_type: str) -> Result:
|
def format_server_response(api_response: ApiResponse, desired_type: str) -> Result:
|
||||||
|
print("Starting format_server_response conversion")
|
||||||
"""Turn an API response into a Result Object"""
|
"""Turn an API response into a Result Object"""
|
||||||
|
|
||||||
# if it's in object format, then convert it,
|
# if it's in object format, then convert it,
|
||||||
|
|
@ -33,28 +35,35 @@ def format_server_response(api_response: ApiResponse, desired_type: str) -> Resu
|
||||||
logger.error("Can't convert server response.")
|
logger.error("Can't convert server response.")
|
||||||
return invalid_server_format()
|
return invalid_server_format()
|
||||||
|
|
||||||
conversion_worked, server_reply = validate_model(ServerReply, raw_reply)
|
validated_model, server_reply = validate_model(ServerReply, raw_reply)
|
||||||
|
|
||||||
if not conversion_worked:
|
if not validated_model:
|
||||||
logger.error(f"Invalid structure for ServerReply. The original raw reply was {raw_reply}")
|
logger.error(f"Invalid structure for ServerReply. The original raw reply was {raw_reply}")
|
||||||
return invalid_server_format(error_msg=server_reply)
|
return invalid_server_format(error_msg=server_reply)
|
||||||
|
|
||||||
# Sanity check:
|
# Failure:
|
||||||
|
if not server_reply.valid:
|
||||||
|
logger.error(f"invalid server reply: {server_reply.error_type}")
|
||||||
|
logger.error(f"invalid server reply: {server_reply.message}")
|
||||||
|
final_return = translate_server_failure(server_reply)
|
||||||
|
|
||||||
|
print(f"final_return is {final_return}")
|
||||||
|
return final_return # result object
|
||||||
|
|
||||||
|
print("Server claims the result was valid, let's check if it has the data type")
|
||||||
if not hasattr(server_reply, desired_type):
|
if not hasattr(server_reply, desired_type):
|
||||||
error_msg = "Developer Error: You're asking for a data type that isn't in the object!"
|
error_msg = "Developer Error: You're asking for a data type that isn't in the object!"
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=error_msg)
|
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=error_msg)
|
||||||
|
|
||||||
# Success! Extract and Return Data:
|
data = getattr(server_reply, desired_type)
|
||||||
if server_reply.valid:
|
if data:
|
||||||
data = getattr(server_reply, desired_type)
|
|
||||||
return Result(valid=True, data=data)
|
return Result(valid=True, data=data)
|
||||||
|
else:
|
||||||
|
return Result(valid=False, error_type=ResultError.MISSING_DATA, message="Server Replied it was valid, but failed to provide the data.")
|
||||||
|
|
||||||
# Failure:
|
|
||||||
logger.error(f"invalid server reply: {server_reply.error_type}")
|
# return Result(valid=False, error_type=error_type, message=server_reply.message)
|
||||||
logger.error(f"invalid server reply: {server_reply.message}")
|
|
||||||
error_type = translate_server_failure(server_reply.error_type)
|
|
||||||
return Result(valid=False, error_type=error_type, message=server_reply.message)
|
|
||||||
|
|
||||||
|
|
||||||
def translate_server_failure(server_reply: ServerReply) -> Result:
|
def translate_server_failure(server_reply: ServerReply) -> Result:
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,13 @@ def register_wireguard_session(
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
raise ConnectionError(error_msg)
|
raise ConnectionError(error_msg)
|
||||||
|
|
||||||
wireguard_configuration = api_result.data
|
# 2nd Layer Translation:
|
||||||
print(f"wireguard_configuration type is {type(wireguard_configuration)}")
|
result = format_server_response(api_response=api_result, desired_type="data")
|
||||||
# print(f"wireguard_configuration value is {wireguard_configuration}")
|
if not result.valid:
|
||||||
|
# KILLING THE RESULT FOR NOW. Later, replace this error raise with the return of data,
|
||||||
if isinstance(wireguard_configuration, dict):
|
raise InvalidSubscriptionError(result.message)
|
||||||
logger.error("Server isn't returning a WG config, it's trying to tell you a ServerReply message...")
|
|
||||||
return handle_config_error(wireguard_configuration)
|
wireguard_configuration = result.data
|
||||||
|
|
||||||
if wireguard_configuration is None:
|
if wireguard_configuration is None:
|
||||||
raise InvalidSubscriptionError()
|
raise InvalidSubscriptionError()
|
||||||
|
|
@ -76,14 +76,25 @@ def register_wireguard_session(
|
||||||
return Result(valid=True)
|
return Result(valid=True)
|
||||||
|
|
||||||
|
|
||||||
|
# over-engineering:
|
||||||
|
|
||||||
def handle_config_error(wireguard_configuration: str|dict) -> Result:
|
# print(f"wireguard_configuration type is {type(wireguard_configuration)}")
|
||||||
"""The server gave the wireguard config in an invalid format. First convert it to get the error."""
|
# # print(f"wireguard_configuration value is {wireguard_configuration}")
|
||||||
server_reply = format_server_response(wireguard_configuration, "message")
|
|
||||||
if server_reply.valid:
|
# if isinstance(wireguard_configuration, dict):
|
||||||
return server_reply
|
# print(f"wireguard_configuration is {type(wireguard_configuration)}")
|
||||||
else:
|
# print(f"wireguard_configuration is {wireguard_configuration}")
|
||||||
return Result(valid=False, error_type=ResultError.NODE_ERROR, message="server-side error with wireguard config format.")
|
# logger.error("Server isn't returning a WG config, it's trying to tell you a ServerReply message...")
|
||||||
|
# return format_server_response(wireguard_configuration, "message")
|
||||||
|
|
||||||
|
|
||||||
|
# def handle_config_error(wireguard_configuration: str|dict) -> Result:
|
||||||
|
# """The server gave the wireguard config in an invalid format. First convert it to get the error."""
|
||||||
|
# server_reply = format_server_response(wireguard_configuration, "message")
|
||||||
|
# if server_reply.valid:
|
||||||
|
# return server_reply
|
||||||
|
# else:
|
||||||
|
# return Result(valid=False, error_type=ResultError.NODE_ERROR, message="server-side error with wireguard config format.")
|
||||||
|
|
||||||
|
|
||||||
def _generate_wireguard_keys() -> dict:
|
def _generate_wireguard_keys() -> dict:
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,7 @@ def _ensure_wireguard_configured(
|
||||||
logger.info(f"[CONNECTION] Checking if the profile already has a wg config..")
|
logger.info(f"[CONNECTION] Checking if the profile already has a wg config..")
|
||||||
if not profile.has_wireguard_configuration():
|
if not profile.has_wireguard_configuration():
|
||||||
logger.info(f"[CONNECTION] Profile does NOT have WG keys and it needs it. Registering a NEW wg session..")
|
logger.info(f"[CONNECTION] Profile does NOT have WG keys and it needs it. Registering a NEW wg session..")
|
||||||
register_wireguard_session(profile, connection_observer=connection_observer)
|
registry_result = register_wireguard_session(profile, connection_observer=connection_observer)
|
||||||
|
|
||||||
|
|
||||||
def _establish_with_renegotiation(
|
def _establish_with_renegotiation(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from core.infrastructure.thread_dispatch import MainThreadDispatcher
|
from core.infrastructure.thread_dispatch import MainThreadDispatcher
|
||||||
from core.services.subscriptions.subscriptions_by_protocol import check_paid
|
from core.services.subscriptions.subscriptions_by_protocol import check_paid, mark_as_paid
|
||||||
|
|
||||||
from core.controllers.tickets.TicketPayController import check_if_ticket_paid
|
from core.controllers.tickets.TicketPayController import check_if_ticket_paid
|
||||||
|
|
||||||
|
|
@ -24,13 +24,13 @@ MAX_FAILED_CONNECTIONS = 8
|
||||||
class CheckPaidTimer:
|
class CheckPaidTimer:
|
||||||
_instance = None # CLASS VARIABLE - survives across __init__ calls
|
_instance = None # CLASS VARIABLE - survives across __init__ calls
|
||||||
|
|
||||||
def __new__(cls, view_callback: Callable, billing_code: str, ui_dispatcher: MainThreadDispatcher, payment_type: PaymentType, connection_observer: ConnectionObserver):
|
def __new__(cls, view_callback: Callable, billing_code: str, ui_dispatcher: MainThreadDispatcher, payment_type: PaymentType, connection_observer: ConnectionObserver, profile_id: int):
|
||||||
"""Called before __init__ — controls instance creation"""
|
"""Called before __init__ — controls instance creation"""
|
||||||
if cls._instance is None:
|
if cls._instance is None:
|
||||||
cls._instance = super().__new__(cls)
|
cls._instance = super().__new__(cls)
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
def __init__(self, view_callback: Callable, billing_code: str, ui_dispatcher: MainThreadDispatcher, payment_type: PaymentType, connection_observer: ConnectionObserver):
|
def __init__(self, view_callback: Callable, billing_code: str, ui_dispatcher: MainThreadDispatcher, payment_type: PaymentType, connection_observer: ConnectionObserver, profile_id: int):
|
||||||
# Guard: makes sure this entire class only runs once
|
# Guard: makes sure this entire class only runs once
|
||||||
if hasattr(self, '_initialized'):
|
if hasattr(self, '_initialized'):
|
||||||
return
|
return
|
||||||
|
|
@ -42,6 +42,7 @@ class CheckPaidTimer:
|
||||||
self.view_callback = view_callback
|
self.view_callback = view_callback
|
||||||
self.ui_dispatcher = ui_dispatcher
|
self.ui_dispatcher = ui_dispatcher
|
||||||
self.billing_code = billing_code
|
self.billing_code = billing_code
|
||||||
|
self.profile_id = profile_id
|
||||||
self.connection_observer = connection_observer
|
self.connection_observer = connection_observer
|
||||||
self.payment_type = payment_type
|
self.payment_type = payment_type
|
||||||
self.failed_connections = 0
|
self.failed_connections = 0
|
||||||
|
|
@ -99,7 +100,15 @@ class CheckPaidTimer:
|
||||||
if result.valid:
|
if result.valid:
|
||||||
print("PAID! Stopping timer")
|
print("PAID! Stopping timer")
|
||||||
self.stop_polling()
|
self.stop_polling()
|
||||||
message = "paid"
|
|
||||||
|
# SAVE:
|
||||||
|
marked = mark_as_paid(profile_id=self.profile_id)
|
||||||
|
if not marked.valid:
|
||||||
|
message = marked.message
|
||||||
|
else:
|
||||||
|
message = "Paid! This invoice is paid"
|
||||||
|
|
||||||
|
# UPDATE UI:
|
||||||
self.view_callback(paid=True, stopped=True, message=message)
|
self.view_callback(paid=True, stopped=True, message=message)
|
||||||
|
|
||||||
# not yet paid:
|
# not yet paid:
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ from core.models.pydantic_models.ServerReply import ServerReply, ServerError, Su
|
||||||
from core.models.Subscription import Subscription
|
from core.models.Subscription import Subscription
|
||||||
from core.Constants import Constants
|
from core.Constants import Constants
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
def check_paid(billing_code: str, connection_observer: ConnectionObserver) -> Result:
|
def check_paid(billing_code: str, connection_observer: ConnectionObserver) -> Result:
|
||||||
"""Evaluates Payment Status from the Server"""
|
"""Evaluates Payment Status from the Server"""
|
||||||
|
|
@ -17,7 +18,6 @@ def check_paid(billing_code: str, connection_observer: ConnectionObserver) -> Re
|
||||||
"billing_code": billing_code
|
"billing_code": billing_code
|
||||||
}
|
}
|
||||||
url = f'{Constants.SP_BASE_URL}/v2/check_paid'
|
url = f'{Constants.SP_BASE_URL}/v2/check_paid'
|
||||||
print(f"url is {url}")
|
|
||||||
|
|
||||||
api_response = connect.single_endpoint(
|
api_response = connect.single_endpoint(
|
||||||
method="post",
|
method="post",
|
||||||
|
|
@ -162,7 +162,24 @@ def get_profile_subscription(profile_id: int) -> Subscription:
|
||||||
return profile.subscription
|
return profile.subscription
|
||||||
|
|
||||||
|
|
||||||
def save_billing_code(profile_id: int, billing_code: str, expires_at: str) -> Result:
|
def mark_as_paid(profile_id: int) -> Result:
|
||||||
|
"""Conclude the payment phase, by marking the sub as paid"""
|
||||||
|
|
||||||
|
logger.info("Marking as paid..")
|
||||||
|
|
||||||
|
# Get profile object:
|
||||||
|
profile = Profile.find_by_id(profile_id)
|
||||||
|
if not profile:
|
||||||
|
error_msg = f"Invalid profile id of {profile_id}"
|
||||||
|
logger.error(error_msg)
|
||||||
|
return Result(valid=False, message=error_msg, error_type=ResultError.INVALID_INPUT)
|
||||||
|
|
||||||
|
profile.subscription.billing_pending = False
|
||||||
|
profile.save()
|
||||||
|
return Result(valid=True)
|
||||||
|
|
||||||
|
|
||||||
|
def save_billing_code(profile_id: int, billing_code: str, expires_at: datetime) -> Result:
|
||||||
"""Checks if the billing code is already saved, and if not, saves it."""
|
"""Checks if the billing code is already saved, and if not, saves it."""
|
||||||
|
|
||||||
logger.info("Saving billing code..")
|
logger.info("Saving billing code..")
|
||||||
|
|
@ -187,32 +204,32 @@ def save_billing_code(profile_id: int, billing_code: str, expires_at: str) -> Re
|
||||||
billing_pending=True
|
billing_pending=True
|
||||||
)
|
)
|
||||||
profile.save()
|
profile.save()
|
||||||
|
return Result(valid=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Legacy system wouldn't create or save Subscription object with {str(billing_code)} and {str(expires_at)} or type {type(expires_at)}, with error: {str(e)}"
|
error_msg = f"Legacy system wouldn't create or save Subscription object with {str(billing_code)} and {str(expires_at)} or type {type(expires_at)}, with error: {str(e)}"
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
return Result(valid=False, message=error_msg, error_type=ResultError.INVALID_INPUT)
|
return Result(valid=False, message=error_msg, error_type=ResultError.INVALID_INPUT)
|
||||||
|
|
||||||
return Result(valid=True)
|
|
||||||
|
|
||||||
|
|
||||||
# # get the payment data singleton:
|
# # get the payment data singleton:
|
||||||
# billing_data = PaymentData(instance_id=profile_id)
|
# billing_data = PaymentData(instance_id=profile_id)
|
||||||
|
|
||||||
# # new
|
# # new
|
||||||
# if billing_data.billing_code is None:
|
# if billing_data.billing_code is None:
|
||||||
# billing_data.billing_code = billing_code
|
# billing_data.billing_code = billing_code
|
||||||
# billing_data.save()
|
# billing_data.save()
|
||||||
# logger.info("saved billing_code")
|
# logger.info("saved billing_code")
|
||||||
# return Result(valid=True)
|
# return Result(valid=True)
|
||||||
|
|
||||||
# # Already exists and is different:
|
# # Already exists and is different:
|
||||||
# if regular_billing.billing_code != billing_code:
|
# if regular_billing.billing_code != billing_code:
|
||||||
# error_msg = "Critical Error! Billing codes do NOT match"
|
# error_msg = "Critical Error! Billing codes do NOT match"
|
||||||
# logger.error(error_msg)
|
# logger.error(error_msg)
|
||||||
# return Result(valid=False, error_type=ResultError.UNKNOWN, message=error_msg)
|
# return Result(valid=False, error_type=ResultError.UNKNOWN, message=error_msg)
|
||||||
|
|
||||||
# # already saved:
|
# # already saved:
|
||||||
# return Result(valid=True, message="Already saved.")
|
# return Result(valid=True, message="Already saved.")
|
||||||
|
|
||||||
|
|
||||||
def return_pre_existing_payment_data(profile_id: int, subscription: SubscriptionInvoice) -> Result:
|
def return_pre_existing_payment_data(profile_id: int, subscription: SubscriptionInvoice) -> Result:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue