From b2c8794ec806385d1ebad498a46545066518667d Mon Sep 17 00:00:00 2001 From: John Date: Wed, 28 Jan 2026 13:13:57 +0100 Subject: [PATCH] update: added sms p2p module --- SMS-Exchange-Linux-GUI | 1 - SMS-Exchange-Linux-GUI/GUI.py | 2468 +++++++++++++++++ SMS-Exchange-Linux-GUI/README.md | 21 + SMS-Exchange-Linux-GUI/SCOPE.md | 17 + ...and_save_json_from_our_api.cpython-311.pyc | Bin 0 -> 2320 bytes ...and_save_json_from_our_api.cpython-312.pyc | Bin 0 -> 2007 bytes .../get_initial_email_data.cpython-311.pyc | Bin 0 -> 2310 bytes .../get_initial_email_data.cpython-312.pyc | Bin 0 -> 1997 bytes .../send_data_to_flask.cpython-311.pyc | Bin 0 -> 13170 bytes .../send_data_to_flask.cpython-312.pyc | Bin 0 -> 10271 bytes .../should_api_be_triggered.cpython-311.pyc | Bin 0 -> 842 bytes .../should_api_be_triggered.cpython-312.pyc | Bin 0 -> 726 bytes .../get_and_save_json_from_our_api.py | 36 + .../api_interaction/get_initial_email_data.py | 38 + .../api_interaction/send_data_to_flask.py | 113 + .../should_api_be_triggered.py | 14 + .../process_the_proxy.cpython-311.pyc | Bin 0 -> 1832 bytes .../process_the_proxy.cpython-312.pyc | Bin 0 -> 2115 bytes ...hich_profile_is_being_used.cpython-311.pyc | Bin 0 -> 394 bytes ...hich_profile_is_being_used.cpython-312.pyc | Bin 0 -> 1447 bytes .../process_the_proxy.py | 42 + .../which_profile_is_being_used.py | 25 + ...erate_random_number_string.cpython-311.pyc | Bin 0 -> 1324 bytes ...erate_random_number_string.cpython-312.pyc | Bin 0 -> 1133 bytes .../load_or_setup_config.cpython-311.pyc | Bin 0 -> 2433 bytes .../load_or_setup_config.cpython-312.pyc | Bin 0 -> 2134 bytes .../__pycache__/local_logs.cpython-311.pyc | Bin 0 -> 10803 bytes .../__pycache__/local_logs.cpython-312.pyc | Bin 0 -> 8886 bytes .../search_or_setup_json.cpython-311.pyc | Bin 0 -> 4260 bytes .../search_or_setup_json.cpython-312.pyc | Bin 0 -> 3620 bytes .../generate_random_number_string.py | 16 + .../load_or_setup_config.py | 54 + .../local_data_operations/local_logs.py | 290 ++ .../search_or_setup_json.py | 74 + .../convert_to_dictonary.cpython-311.pyc | Bin 0 -> 947 bytes .../convert_to_dictonary.cpython-312.pyc | Bin 0 -> 696 bytes .../extract_a_list_of_values.cpython-311.pyc | Bin 0 -> 1478 bytes .../extract_a_list_of_values.cpython-312.pyc | Bin 0 -> 1289 bytes ...d_from_text_file_into_list.cpython-311.pyc | Bin 0 -> 1101 bytes ...d_from_text_file_into_list.cpython-312.pyc | Bin 0 -> 770 bytes .../process_api_data/convert_to_dictonary.py | 13 + .../extract_a_list_of_values.py | 31 + .../read_from_text_file_into_list.py | 18 + .../filter_email_names.cpython-311.pyc | Bin 0 -> 692 bytes .../filter_email_names.cpython-312.pyc | Bin 0 -> 578 bytes .../load_email_operators.cpython-311.pyc | Bin 0 -> 1338 bytes .../load_email_operators.cpython-312.pyc | Bin 0 -> 1028 bytes .../process_email_data/filter_email_names.py | 10 + .../load_email_operators.py | 13 + SMS-Exchange-Linux-GUI/requirements.txt | 19 + 50 files changed, 3312 insertions(+), 1 deletion(-) delete mode 160000 SMS-Exchange-Linux-GUI create mode 100755 SMS-Exchange-Linux-GUI/GUI.py create mode 100755 SMS-Exchange-Linux-GUI/README.md create mode 100755 SMS-Exchange-Linux-GUI/SCOPE.md create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_and_save_json_from_our_api.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_and_save_json_from_our_api.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_initial_email_data.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_initial_email_data.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/__pycache__/send_data_to_flask.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/__pycache__/send_data_to_flask.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/__pycache__/should_api_be_triggered.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/__pycache__/should_api_be_triggered.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/get_and_save_json_from_our_api.py create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/get_initial_email_data.py create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/send_data_to_flask.py create mode 100755 SMS-Exchange-Linux-GUI/api_interaction/should_api_be_triggered.py create mode 100755 SMS-Exchange-Linux-GUI/interact_with_rest_of_app/__pycache__/process_the_proxy.cpython-311.pyc create mode 100644 SMS-Exchange-Linux-GUI/interact_with_rest_of_app/__pycache__/process_the_proxy.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/interact_with_rest_of_app/__pycache__/which_profile_is_being_used.cpython-311.pyc create mode 100644 SMS-Exchange-Linux-GUI/interact_with_rest_of_app/__pycache__/which_profile_is_being_used.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/interact_with_rest_of_app/process_the_proxy.py create mode 100755 SMS-Exchange-Linux-GUI/interact_with_rest_of_app/which_profile_is_being_used.py create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/generate_random_number_string.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/generate_random_number_string.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/load_or_setup_config.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/load_or_setup_config.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/local_logs.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/local_logs.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/search_or_setup_json.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/search_or_setup_json.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/generate_random_number_string.py create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/load_or_setup_config.py create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/local_logs.py create mode 100755 SMS-Exchange-Linux-GUI/local_data_operations/search_or_setup_json.py create mode 100755 SMS-Exchange-Linux-GUI/process_api_data/__pycache__/convert_to_dictonary.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_api_data/__pycache__/convert_to_dictonary.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_api_data/__pycache__/extract_a_list_of_values.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_api_data/__pycache__/extract_a_list_of_values.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_api_data/__pycache__/read_from_text_file_into_list.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_api_data/__pycache__/read_from_text_file_into_list.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_api_data/convert_to_dictonary.py create mode 100755 SMS-Exchange-Linux-GUI/process_api_data/extract_a_list_of_values.py create mode 100755 SMS-Exchange-Linux-GUI/process_api_data/read_from_text_file_into_list.py create mode 100755 SMS-Exchange-Linux-GUI/process_email_data/__pycache__/filter_email_names.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_email_data/__pycache__/filter_email_names.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_email_data/__pycache__/load_email_operators.cpython-311.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_email_data/__pycache__/load_email_operators.cpython-312.pyc create mode 100755 SMS-Exchange-Linux-GUI/process_email_data/filter_email_names.py create mode 100755 SMS-Exchange-Linux-GUI/process_email_data/load_email_operators.py create mode 100755 SMS-Exchange-Linux-GUI/requirements.txt diff --git a/SMS-Exchange-Linux-GUI b/SMS-Exchange-Linux-GUI deleted file mode 160000 index d114604..0000000 --- a/SMS-Exchange-Linux-GUI +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d1146046c0a222d1c278cda5c8852980d79ddd23 diff --git a/SMS-Exchange-Linux-GUI/GUI.py b/SMS-Exchange-Linux-GUI/GUI.py new file mode 100755 index 0000000..914f935 --- /dev/null +++ b/SMS-Exchange-Linux-GUI/GUI.py @@ -0,0 +1,2468 @@ +# Loading and using the config +from local_data_operations.search_or_setup_json import search_key_in_json +from local_data_operations.load_or_setup_config import load_or_setup_config, replace_config_value, setup_path_to_dump_initial_api_data, load_or_setup_local_api_data_folder +from local_data_operations.local_logs import get_profile_location_and_proxy_status_as_tuple, create_or_add_to_profile_config, return_all_locally_saved_orders_for_the_current_profile, delete_an_order, setup_email_config, get_email_data, wipe_email_data, wipe_location_and_proxy, wipe_entire_profile_data +# generate buyer id: +from local_data_operations.generate_random_number_string import generate_random_number_string + +# manipulating data from the API: +from process_api_data.extract_a_list_of_values import extract_a_list_of_values, get_the_locations_for_a_service +from process_api_data.read_from_text_file_into_list import read_from_text_file_into_list +from process_api_data.convert_to_dictonary import search_by_category + +# manipulating email data to send or recieve from the API: +from api_interaction.get_initial_email_data import get_initial_email_data +from process_email_data.filter_email_names import filter_email_names +from process_email_data.load_email_operators import load_email_operators + +# coordinating with API: +from api_interaction.send_data_to_flask import send_data_to_flask, dispute_send_data_to_flask, check_if_paid_by_sending_data_to_flask, ready_for_code_by_sending_data_to_flask, send_crypto_address_for_refund, restore_an_already_finalized_number +from api_interaction.get_and_save_json_from_our_api import get_and_save_json_from_our_api +from api_interaction.should_api_be_triggered import should_api_be_triggered + +# process the proxy: +from interact_with_rest_of_app.process_the_proxy import process_the_proxy + +# Generic imports: + +# async: +import aiohttp +from aiohttp import ClientConnectorError, ClientResponseError +import asyncio + +# basic tools: +import os +import sys +import json + +# error log, which line: +import traceback +import interact_with_rest_of_app.which_profile_is_being_used as which_profile_module + +# GUI visual: +from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QComboBox, QPushButton, QSizePolicy, QMessageBox, QListWidget, QGridLayout, QHBoxLayout, QComboBox, QMainWindow, QInputDialog, QLineEdit +from qasync import QEventLoop, asyncSlot +from PyQt6.QtCore import QCoreApplication, QTimer + +# FOR DEBUG UNCOMMENT, if I want to start tracing memory allocations +import tracemalloc +tracemalloc.start() + + +class BuyerPeerPeerGUI(QWidget): + def __init__(self): + super().__init__() + + # Name of the config file for entire app: + self.name_of_config_file = "sms_config.json" + # Load Config data for entire rest of the app to be searched with the 'search_key_in_json' function: + self.config_file_data = load_or_setup_config(self.name_of_config_file) + + # for api data: + self.folder_for_api_data = load_or_setup_local_api_data_folder() + self.email_file_path = f"{self.folder_for_api_data}/email_operators.json" + self.filename_for_locations_data = f"{self.folder_for_api_data}/services_by_type_and_location.json" + + # Commented out format to search config: + # result = search_key_in_json(config_raw_data, "key", default) + + # setup error logs: + self.error_log_file_path = search_key_in_json( + self.config_file_data, "error_log_file_path", "error_log_for_gui.txt") + + self.setWindowTitle("SMS Exchange | HydraVeil") + self.setFixedSize(800, 600) + self.move(100, 100) + + # Set the overall style + self.setStyleSheet("background-color: black; color: white;") + + # set styles for entire project: + self.active_style_box = """ + background-color: #282828; /* Dark background for contrast */ + color: #FFD700; /* Gold color for text */ + font-size: 30px; + font-family: 'Press Start 2P', cursive; /* Retro font */ + border: 3px solid #00FF00; /* Bright green border */ + padding: 15px; /* Increased padding */ + text-align: center; /* Centering text */ + """ + + self.lowkey_style_box = """ + background-color: #444444; /* Darker grey for a muted effect */ + color: #A9A9A9; /* Light grey for text */ + font-size: 30px; + font-family: 'Press Start 2P', cursive; /* Keeping the retro font */ + border: none; /* No border */ + padding: 15px; /* Maintained padding */ + text-align: center; /* Centering text */ + """ + + self.blue_chill_style = """ + QPushButton { + font-size: 30px; + font-weight: normal; + color: #007BFF; /* Bright blue text */ + background-color: transparent; /* No background */ + border: 2px solid #007BFF; /* Blue border */ + border-radius: 5px; /* Slightly rounded corners */ + padding: 10px 15px; /* Vertical and horizontal padding */ + } + QPushButton:hover { + background-color: rgba(0, 123, 255, 0.1); /* Light blue background on hover */ + } + QPushButton:pressed { + background-color: rgba(0, 123, 255, 0.2); /* Darker blue when pressed */ + } + """ + + # Create layout + self.layout = QVBoxLayout() + + # This label style is used in many spots throughout the various pages: + self.label_style = "font-size: 40px; color: white;" + + # Set layout to the main window: + self.setLayout(self.layout) + + # Display to the end-user that it's fetching data, although technically it didn't start doing it yet: + self.label_for_api_fetch = QLabel(f"Fetching Available Services") + self.label_for_api_fetch.setStyleSheet(self.label_style) + self.label_for_api_fetch.setSizePolicy( + # Expanding vertical size policy + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + self.layout.addWidget(self.label_for_api_fetch) + + # We don't want the GUI to not load until after the API call is done, so we schedule an async function to run after the GUI is shown, + QTimer.singleShot(0, self.step_1_run_api_async) + + # Set layout to the main window + self.setLayout(self.layout) + +# Start basic functions section: + def show_error_message(self, message): + msg_box = QMessageBox(self) + msg_box.setIcon(QMessageBox.Icon.Warning) + msg_box.setText(message) + msg_box.setWindowTitle('Error') + msg_box.exec() + + def log_an_error(self, error): + with open(self.error_log_file_path, 'a') as file: + file.write(f'{error}\n') +# End basic functions section + + # We're getting the data from an API, and displaying either the data in lists, or an error message of why it failed to get the data, + @asyncSlot() + async def step_1_run_api_async(self): + period_of_time = 3600 # an hour + # does the user want to use existing data or new data? + are_we_doing_an_api_call = should_api_be_triggered( + self.filename_for_locations_data, period_of_time) + if are_we_doing_an_api_call == False: + # we need to do an API call to get fresh data: + await self.step_2_actually_fetch_data_from_api() + else: + # do NOT do the API call, skip to using the existing local data: + self.after_fetched_data_from_api_is_done() + + async def step_2_actually_fetch_data_from_api(self): + non_binary_of_did_it_get_it_from_api_or_not = await get_and_save_json_from_our_api(self.filename_for_locations_data) + if non_binary_of_did_it_get_it_from_api_or_not == "worked": + + self.label_for_api_fetch.setText("Fetching Email Operators") + next_get_email_data = await get_initial_email_data(self.email_file_path) + if next_get_email_data == "worked": + self.after_fetched_data_from_api_is_done() + else: + self.display_error_message_from_failed_connection( + next_get_email_data) + else: + self.display_error_message_from_failed_connection( + non_binary_of_did_it_get_it_from_api_or_not) + + def display_error_message_from_failed_connection(self, error_message_content): + # Format the Label for a long message, and Display the Error of why it failed to get the data: + self.label_for_api_fetch.setStyleSheet("font-size: 40px;") + self.label_for_api_fetch.setWordWrap(True) + self.label_for_api_fetch.setFixedWidth(800) + self.label_for_api_fetch.setText(str(error_message_content)) + + def after_fetched_data_from_api_is_done(self): + try: + # Check if the label exists and is not already hidden + if self.label_for_api_fetch is not None: + if not self.label_for_api_fetch.isHidden(): + self.label_for_api_fetch.hide() + else: + pass + except Exception as e: + pass + # self.show_error_message(f"An unexpected error occurred: {e}") + # self.log_an_error(e) + + # Generate ID: + self.peer_to_peer_billing_id = generate_random_number_string() + + # Display the ID (with that label style declared in the init section): + label_for_peer_to_peer_billing_id = QLabel( + f"Your P2P ID is: {self.peer_to_peer_billing_id}") + label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style) + label_for_peer_to_peer_billing_id.setSizePolicy( + # Expanding vertical size policy + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + self.layout.addWidget(label_for_peer_to_peer_billing_id) + + # Create a horizontal layout for the two QListWidgets + self.top_ribbon_h_layout = QHBoxLayout() + + # Add the left column's label, above box: + self.left_label_above_box = QLabel("General Categories") + smaller_sub_label_style = "font-size: 30px; color: grey;" + self.left_label_above_box.setStyleSheet(smaller_sub_label_style) + + # Add the right column's label, above box: + self.right_label_above_box = QLabel("Specific Sites") + self.right_label_above_box.setStyleSheet(smaller_sub_label_style) + + self.top_ribbon_h_layout.addWidget(self.left_label_above_box) + self.top_ribbon_h_layout.addWidget(self.right_label_above_box) + self.layout.addLayout(self.top_ribbon_h_layout) + + # Create a horizontal layout for the two QListWidgets + self.h_layout = QHBoxLayout() + + # The initial API call saved the initial data JSON to this path: + with open(self.filename_for_locations_data, 'r') as file: + self.initial_data = json.load(file) + + # Each category on the left, gets the filtered values of the data on the right + self.social_list = extract_a_list_of_values( + self.initial_data, "social") + self.big_tech_list = extract_a_list_of_values( + self.initial_data, "big_tech") + self.business_list = extract_a_list_of_values( + self.initial_data, "business") + self.travel_list = extract_a_list_of_values( + self.initial_data, "travel") + self.AI_list = extract_a_list_of_values(self.initial_data, "AI") + + # Mapping of items to their corresponding lists + self.list_mapping = { + 'social_media': self.social_list, + 'big_tech': self.big_tech_list, + 'business': self.business_list, + 'travel': self.travel_list, + 'AI': self.AI_list + } + + # This is the left category column: + self.list_widget1 = QListWidget() + + # Add items to list_widget1 + self.list_widget1.addItems(self.list_mapping.keys()) + + self.list_widget1.setSelectionMode( + QListWidget.SelectionMode.SingleSelection) + self.list_widget1.setStyleSheet( + "background-color: grey; color: white; font-size: 26px;") + + # Create the second QListWidget + self.list_widget2 = QListWidget() + self.list_widget2.setSelectionMode( + QListWidget.SelectionMode.SingleSelection) + self.list_widget2.setStyleSheet( + "background-color: grey; color: white; font-size: 26px;") + + # Add the QListWidgets to the horizontal layout + self.h_layout.addWidget(self.list_widget1) + self.h_layout.addWidget(self.list_widget2) + + # Set the QListWidget style with larger font size + self.list_widget1.setStyleSheet( + # Adjust font size as needed + "background-color: grey; color: white; font-size: 26px;") + self.list_widget2.setStyleSheet( + # Adjust font size as needed + "background-color: grey; color: white; font-size: 26px;") + + # Connect the item selection change signal to the update method + self.list_widget1.itemClicked.connect(self.on_item_clicked) + self.list_widget2.itemClicked.connect(self.on_right_item_clicked) + + # Create dropdown menus: + self.payment_method_dropdown = QComboBox() + self.location_dropdown = QComboBox() + self.email_dropdown = QComboBox() + + # Populate dropdowns with defaults: + + # Start Cryptocurrency dropdown section: + default_currency = search_key_in_json( + self.config_file_data, "default_currency", False) + if default_currency == False: + payment_methods_list = [ + 'Monero', "Bitcoin_Lightning", "Litecoin", "Bitcoin"] + else: + payment_methods_list = [default_currency] + self.payment_method_dropdown.addItems(payment_methods_list) + # End Cryptocurrency dropdown section + + # Setup Location dropdown: + locations_list = ["Pick a Location"] + self.location_dropdown.addItems(locations_list) + # end Locations dropdown + + # Start EMAIL dropdown section: + # do we already have email data? + packed_email_data = get_email_data() # calls function from local_logs.py + # if we do NOT yet have an email: + if packed_email_data == False or packed_email_data == "error": + self.turn_off_email_option = search_key_in_json( + self.config_file_data, "turn_off_email_option", False) + # did the user disable email in the options? + if self.turn_off_email_option == False: + email_operators_list = load_email_operators( + self.email_file_path) + else: + email_operators_list = ["email disabled"] + # else we already have an email for this profile: + else: + email_operators_list = ["profile already has an email"] + + if email_operators_list is None: + empty_list = ["random"] + self.email_dropdown.addItems(empty_list) + else: + self.email_dropdown.addItems(email_operators_list) + # end Email dropdown + + # Set text color and font size for dropdowns: + self.payment_method_dropdown.setStyleSheet( + "color: white; background-color: green; font-size: 24px;") + self.location_dropdown.setStyleSheet( + "color: white; background-color: red; font-size: 24px;") + self.email_dropdown.setStyleSheet( + "color: black; background-color: white; font-size: 20px;") + + # display the profile status once they select a service: + self.label_for_profile_status = QLabel(f"Profile Status") + self.label_for_profile_status.setStyleSheet( + "font-size: 15px; color: white;") + self.label_for_profile_status.setWordWrap(True) + self.label_for_profile_status.setSizePolicy( + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + # for now hide it. But later, this will appear after they select a service, + self.label_for_profile_status.setVisible(False) + + # Create a button to show selected items + self.button = QPushButton("Residential Proxy, SMS, and Email! (€11)") + # Set background and text color self.button.clicked.connect(self.show_selected) + self.button.setStyleSheet( + "font-size: 30px; padding: 15px; background-color: green; color: yellow;") + self.button.clicked.connect(self.on_button_click) + + # Button to clear selections + self.just_sms_button = QPushButton("SMS Only (€5)") + # self.just_sms_button.setStyleSheet("font-size: 20px; padding: 15px; background-color: grey; color: black;") # Set background and text color self.button.clicked.connect(self.show_selected) + + self.just_sms_button.setStyleSheet(""" + QPushButton { + font-size: 20px; + font-weight: bold; + color: #218838; /* dark green text */ + background-color: #ffd700; /* Gold background */ + border: 2px solid #ffcc00; /* Light gold border */ + border-radius: 25px; /* Rounded corners */ + padding: 15px 30px; /* Generous padding */ + text-align: center; /* Center the text */ + } + QPushButton:hover { + background-color: #f0c36d; /* Lighter gold on hover */ + border-color: #ffdb58; /* Change border color on hover */ + } + QPushButton:pressed { + background-color: #c8a23b; /* Darker gold when pressed */ + border-color: #b89a26; /* Darker border when pressed */ + } + """) + + self.just_sms_button.clicked.connect(self.just_sms_no_proxy) + + # Create a button for more options, including to allow the previous sessions to be restored: + self.more_options_button = QPushButton("More Options") + # self.more_options_button.setStyleSheet("font-size: 15px; padding: 10px; background-color: grey; color: black;") # Set background and text color self.button.clicked.connect(self.show_selected) + self.more_options_button.clicked.connect( + self.update_ui_to_display_more_options) + self.more_options_button.setStyleSheet(self.blue_chill_style) + + # Add widgets to layout: + self.layout.addLayout(self.h_layout) + + self.layout.addWidget(self.payment_method_dropdown) + self.layout.addWidget(self.location_dropdown) + self.layout.addWidget(self.email_dropdown) + + self.layout.addWidget(self.label_for_profile_status) + + self.layout.addWidget(self.button) + self.layout.addWidget(self.just_sms_button) + + # but hide the send button till they fill in the fields: + self.button.setVisible(False) + self.just_sms_button.setVisible(False) + + self.layout.addWidget(self.more_options_button) + self.service_literally_clicked_already = "no" + +# Start: Display More Options Menu: + def update_ui_to_display_more_options(self): + try: + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + # Clear all widgets from the horizontal layout + for i in reversed(range(self.h_layout.count())): + item = self.h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + for i in reversed(range(self.top_ribbon_h_layout.count())): + item = self.top_ribbon_h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + except: + pass + + finally: + # Get Locally Saved Profile Data: + profile_location_and_proxy_tuple = get_profile_location_and_proxy_status_as_tuple() + + # Find out if it's a Pre-existing Profile. It's possible the person went to the menu before selecting a service + if profile_location_and_proxy_tuple == False: + profile_menu_data = "Brand New Profile.\nNo Location Yet." + else: + # Pre-existing profiles have a location already,: + profile_location, profile_proxy_status = profile_location_and_proxy_tuple + profile_menu_data = f"Profile Location: {profile_location}" + + # Options Menu Profile Display + self.options_menu_label = QLabel(f"Menu\n{profile_menu_data}") + self.options_menu_label.setStyleSheet(self.active_style_box) + self.options_menu_label.setWordWrap(True) + self.layout.addWidget(self.options_menu_label) + + # restore previous interrupted session button: + self.restore_previous_button = QPushButton( + "Restore a Previous Session") + self.restore_previous_button.setStyleSheet( + "font-size: 40px; padding: 10px; background-color: green; color: yellow;") + self.restore_previous_button.clicked.connect( + self.restore_previous_session) + self.layout.addWidget(self.restore_previous_button) + + # email options button: + self.get_only_an_email_button = QPushButton("Email Options") + self.get_only_an_email_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: blue;") + self.get_only_an_email_button.clicked.connect( + self.email_options_ui) + self.layout.addWidget(self.get_only_an_email_button) + + # proxy info button: + self.proxy_options_button = QPushButton( + "Proxy and Profile Options") + self.proxy_options_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: black; color: white;") + self.proxy_options_button.clicked.connect( + self.update_ui_for_proxy_data) + self.layout.addWidget(self.proxy_options_button) + + # disable local logs button: + self.disable_local_logs_button = QPushButton("SMS Preferences") + self.disable_local_logs_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: white; color: black;") + self.disable_local_logs_button.clicked.connect( + self.update_ui_to_change_local_logs) + self.layout.addWidget(self.disable_local_logs_button) + + # change default cryptocurrency button: + self.change_default_currency_button = QPushButton( + "Change Default Cryptocurrency") + self.change_default_currency_button.setStyleSheet( + self.blue_chill_style) + self.change_default_currency_button.clicked.connect( + self.update_ui_to_change_default_currency) + self.layout.addWidget(self.change_default_currency_button) + + # frequency button: + # self.connection_frequency_button = QPushButton("Connection Frequency") + # self.connection_frequency_button.setStyleSheet("font-size: 30px; padding: 10px; background-color: white; color: black;") + # self.connection_frequency_button.clicked.connect(self.update_ui_to_change_local_logs) + # self.layout.addWidget(self.connection_frequency_button) + + # return to main page button: + self.return_to_the_main_page_button = QPushButton( + "Return to the Main Page") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: green; color: yellow;") + self.return_to_the_main_page_button.clicked.connect( + self.update_ui_to_return_to_the_main_page) + self.layout.addWidget(self.return_to_the_main_page_button) + + def update_ui_for_proxy_data(self): + self.clear_the_main_page_ui() + + # Options Menu Profile Display + self.options_menu_label = QLabel(f"Proxy Menu") + self.options_menu_label.setStyleSheet(self.active_style_box) + self.options_menu_label.setWordWrap(True) + self.layout.addWidget(self.options_menu_label) + + # Get Locally Saved Profile Data: + profile_location_and_proxy_tuple = get_profile_location_and_proxy_status_as_tuple() + + # Find out if it's a Pre-existing Profile. It's possible the person went to the menu before selecting a service + if profile_location_and_proxy_tuple == False: + profile_menu_data = "This Profile does not have a Location Yet." + else: + # Pre-existing profiles have a location already,: + profile_location, profile_proxy_status = profile_location_and_proxy_tuple + profile_menu_data = f"Profile Location: {profile_location}" + + # proxy data wipe button: + self.proxy_wipe_button = QPushButton("Delete Proxy Only") + self.proxy_wipe_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: white;") + self.proxy_wipe_button.clicked.connect(self.wipe_email_data_in_gui) + self.layout.addWidget(self.proxy_wipe_button) + + # proxy data wipe button: + self.wipe_entire_profile_button = QPushButton( + "Wipe entire Profile") + self.wipe_entire_profile_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: black;") + self.wipe_entire_profile_button.clicked.connect( + self.wipe_entire_profile_in_gui) + self.layout.addWidget(self.wipe_entire_profile_button) + + self.options_menu_label.setText(f"{profile_menu_data}") + + # return to main page button: + self.return_to_the_main_page_button = QPushButton( + "Return to the Main Page") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: green; color: yellow;") + self.return_to_the_main_page_button.clicked.connect( + self.update_ui_to_return_to_the_main_page) + self.layout.addWidget(self.return_to_the_main_page_button) + + def wipe_entire_profile_in_gui(self): + # Create a message box with warning icon + msg_box = QMessageBox() + msg_box.setIcon(QMessageBox.Icon.Warning) + msg_box.setText( + "Are you sure you want to delete your proxy and SMS data?") + msg_box.setWindowTitle("Confirmation") + + # delete/cancel buttons + delete_button = msg_box.addButton( + "Delete", QMessageBox.ButtonRole.AcceptRole) + msg_box.addButton("Cancel", QMessageBox.ButtonRole.RejectRole) + msg_box.exec() + + # Determine which button was pressed + if msg_box.clickedButton() == delete_button: + print("delete") + did_it_wipe = wipe_entire_profile_data() + if did_it_wipe == True: + self.options_menu_label.setText("Blank Location") + else: + self.options_menu_label.setText( + "Error! Profile wipe failed, please do it manually.") + else: + pass # Do nothing on Cancel + + def wipe_email_data_in_gui(self): + # call the function from local_logs module. (it returns true if deletes it OR also true if it doesn't exist) + did_it_wipe = wipe_location_and_proxy() + if did_it_wipe == True: + self.update_ui_to_return_to_the_main_page() + else: + self.options_menu_label.setText( + "Error! Failed to Wipe Location Data") + + def update_ui_to_return_to_the_main_page(self): + try: + # Call the method to remove the grid layout + self.remove_grid_layout() + except: + pass + try: + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + except: + pass + finally: + self.after_fetched_data_from_api_is_done() + + def clear_the_main_page_ui(self): + try: + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + except: + pass + + def update_ui_to_change_default_currency(self): + self.clear_the_main_page_ui() + + # Label to display the email: + self.instructions_for_currency = QLabel( + f"Select From the Dropdown Below:") + self.instructions_for_currency.setStyleSheet(self.active_style_box) + self.instructions_for_currency.setWordWrap(True) + self.layout.addWidget(self.instructions_for_currency) + + self.payment_method_dropdown = QComboBox() + self.payment_method_dropdown.setStyleSheet( + "color: white; background-color: green; font-size: 50px;") + payment_methods_list = [ + 'Monero', "Bitcoin_Lightning", "Litecoin", "Bitcoin"] + self.payment_method_dropdown.clear() + self.payment_method_dropdown.addItems(payment_methods_list) + self.payment_method_dropdown.activated.connect( + self.update_ui_for_currency_pick) + self.layout.addWidget(self.payment_method_dropdown) + + self.instructions_for_currency_two = QLabel(f"Then:") + self.instructions_for_currency_two.setStyleSheet(self.lowkey_style_box) + self.instructions_for_currency_two.setWordWrap(True) + self.layout.addWidget(self.instructions_for_currency_two) + + # return to main page button: + self.return_to_the_main_page_button = QPushButton("Apply the Change") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: green; color: yellow;") + self.return_to_the_main_page_button.clicked.connect( + self.implement_the_default_currency_change) + self.layout.addWidget(self.return_to_the_main_page_button) + + # return to main page button: + self.return_to_the_main_page_button = QPushButton( + "Nevermind. Return to Main Page") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: black;") + self.return_to_the_main_page_button.clicked.connect( + self.update_ui_to_return_to_the_main_page) + self.layout.addWidget(self.return_to_the_main_page_button) + + def update_ui_for_currency_pick(self): + self.instructions_for_currency.setStyleSheet(self.lowkey_style_box) + self.instructions_for_currency_two.setStyleSheet(self.active_style_box) + + def implement_the_default_currency_change(self): + chosen_payment_method = self.payment_method_dropdown.currentText() + + # It's calling on a module to change the config JSON: + self.config_file_data = replace_config_value( + self.name_of_config_file, "default_currency", chosen_payment_method) + + # return back: + self.update_ui_to_return_to_the_main_page() + + def email_options_ui(self): + self.clear_the_main_page_ui() + + self.zero_set_of_instructions = QLabel( + f"Do you want to see options for THIS profile or ALL profiles?") + self.zero_set_of_instructions.setStyleSheet(self.active_style_box) + self.zero_set_of_instructions.setWordWrap(True) + self.layout.addWidget(self.zero_set_of_instructions) + + self.display_email_data_button = QPushButton( + "THIS Profile's Email Data") + self.display_email_data_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: blue; color: black;") + self.display_email_data_button.clicked.connect( + self.display_profile_email_data) + self.layout.addWidget(self.display_email_data_button) + + self.all_profiles_email_options_button = QPushButton( + "ALL profiles Email Options") + self.all_profiles_email_options_button.setStyleSheet( + "font-size: 30px; padding: 20px; background-color: black; color: white;") + self.all_profiles_email_options_button.clicked.connect( + self.all_profile_email_options_ui) + self.layout.addWidget(self.all_profiles_email_options_button) + + # return to main page button: + self.return_to_the_main_page_button = QPushButton( + "Nevermind. Return to Main Page") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: black;") + self.return_to_the_main_page_button.clicked.connect( + self.update_ui_to_return_to_the_main_page) + self.layout.addWidget(self.return_to_the_main_page_button) + + def display_profile_email_data(self): + self.clear_the_main_page_ui() + # this is a default flag: + we_have_email_data = False # by default + + packed_email_data = get_email_data() # calls function from local_logs.py + if packed_email_data == False: + message_for_end_user = "Your current profile has no email data yet." + elif packed_email_data == "error": + message_for_end_user = "There was some kind of internal error with loading the email data" + else: + we_have_email_data = True + self.email_operator_in_GUI, self.full_email_in_GUI, self.email_url_in_GUI, self.email_password_in_GUI = packed_email_data + message_for_end_user = f""" +This Profile has an Email: + +Email Address: {self.full_email_in_GUI} +Web Client URL: {self.email_url_in_GUI} +Server Operator: {self.email_operator_in_GUI} + """ + + # First Label displays errors OR data + self.first_set_of_instructions = QLabel(f"{message_for_end_user}") + self.first_set_of_instructions.setStyleSheet(self.active_style_box) + self.first_set_of_instructions.setWordWrap(True) + self.layout.addWidget(self.first_set_of_instructions) + + if we_have_email_data == True: + # Label to copy-paste the email url: + self.copy_email_url_button = QPushButton("Copy Web Client URL") + self.copy_email_url_button.setStyleSheet( + "font-size: 15px; padding: 15px; background-color: green; color: yellow;") + self.copy_email_url_button.clicked.connect( + self.copy_email_url_function) + self.layout.addWidget(self.copy_email_url_button) + + # Label to copy-paste the email: + self.copy_full_email_button = QPushButton("Copy Email") + self.copy_full_email_button.setStyleSheet( + "font-size: 20px; padding: 15px; background-color: green; color: yellow;") + self.copy_full_email_button.clicked.connect( + self.copy_full_email_function) + self.layout.addWidget(self.copy_full_email_button) + + # Label to copy-paste the email password: + self.copy_email_password_button = QPushButton( + "Copy Email's Password") + self.copy_email_password_button.setStyleSheet( + "font-size: 20px; padding: 15px; background-color: green; color: yellow;") + self.copy_email_password_button.clicked.connect( + self.copy_email_password_function) + self.layout.addWidget(self.copy_email_password_button) + + self.wipe_email_data_button = QPushButton("Wipe this Email Data") + self.wipe_email_data_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: grey;") + self.wipe_email_data_button.clicked.connect( + self.call_upon_wipe_email_data_function) + self.layout.addWidget(self.wipe_email_data_button) + + # return to main page button: + self.return_to_the_main_page_button = QPushButton( + "Return to Main Page") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: black;") + self.return_to_the_main_page_button.clicked.connect( + self.update_ui_to_return_to_the_main_page) + self.layout.addWidget(self.return_to_the_main_page_button) + + def call_upon_wipe_email_data_function(self): + did_it_wipe = wipe_email_data() + if did_it_wipe == True: + message_for_end_user = "Hillary Clinton would be proud. Email data wiped." + self.copy_email_url_button.setVisible(False) + self.copy_full_email_button.setVisible(False) + self.copy_email_password_button.setVisible(False) + self.wipe_email_data_button.setVisible(False) + else: + message_for_end_user = "Some kind of File Error. Try to delete it manually" + + self.first_set_of_instructions.setText(message_for_end_user) + + def all_profile_email_options_ui(self): + self.clear_the_main_page_ui() + + # do we have email data? + packed_email_data = get_email_data() # calls function from local_logs.py + if packed_email_data == False or packed_email_data == "error": + email_display_message = f"Do you want email to continue to be offered on the main menu for ALL profiles?" + else: + email_display_message = f"This profile already has an email. But for OTHER profiles, do you want to keep it enabled or disable it?" + + # Label to display instructions + self.first_set_of_instructions = QLabel(f"{email_display_message}") + self.first_set_of_instructions.setStyleSheet(self.active_style_box) + self.first_set_of_instructions.setWordWrap(True) + self.layout.addWidget(self.first_set_of_instructions) + + self.email_preference_dropdown = QComboBox() + self.email_preference_dropdown.setStyleSheet( + "color: white; background-color: green; font-size: 50px;") + list_of_email_preferences = ["yes, enable", "no, disable"] + self.email_preference_dropdown.clear() + self.email_preference_dropdown.addItems(list_of_email_preferences) + self.email_preference_dropdown.activated.connect( + self.show_the_apply_change_button) + self.layout.addWidget(self.email_preference_dropdown) + + self.second_set_of_instructions = QLabel(f"Then Apply it:") + self.second_set_of_instructions.setStyleSheet(self.active_style_box) + self.second_set_of_instructions.setWordWrap(True) + self.second_set_of_instructions.setVisible(False) + self.layout.addWidget(self.second_set_of_instructions) + + self.save_preferences_button = QPushButton("Apply the Change") + self.save_preferences_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: green; color: yellow;") + self.save_preferences_button.clicked.connect( + self.implement_email_disabled_change) + self.save_preferences_button.setVisible(False) + self.layout.addWidget(self.save_preferences_button) + + # return to main page button: + self.return_to_the_main_page_button = QPushButton( + "Nevermind. Return to Main Page") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: black;") + self.return_to_the_main_page_button.clicked.connect( + self.update_ui_to_return_to_the_main_page) + self.layout.addWidget(self.return_to_the_main_page_button) + + def update_ui_to_change_local_logs(self): + self.clear_the_main_page_ui() + + # Label to display change instructions + self.first_set_of_instructions = QLabel( + f"When you get an SMS code, your local computer saves the billing code so you can restore a session if disconnected, or potentially try to get the same phone number again in a future emergency. GOING FORWARD, Do you want to save this data locally? Select from the Green Dropdown below:") + self.first_set_of_instructions.setStyleSheet(self.active_style_box) + self.first_set_of_instructions.setWordWrap(True) + self.layout.addWidget(self.first_set_of_instructions) + + self.local_data_preference_dropdown = QComboBox() + self.local_data_preference_dropdown.setStyleSheet( + "color: white; background-color: green; font-size: 50px;") + list_of_local_data_preferences = ["save codes", "wipe codes"] + self.local_data_preference_dropdown.clear() + self.local_data_preference_dropdown.addItems( + list_of_local_data_preferences) + self.local_data_preference_dropdown.activated.connect( + self.show_the_apply_change_button) + self.layout.addWidget(self.local_data_preference_dropdown) + + self.second_set_of_instructions = QLabel(f"Then Apply it:") + self.second_set_of_instructions.setStyleSheet(self.active_style_box) + self.second_set_of_instructions.setWordWrap(True) + self.second_set_of_instructions.setVisible(False) + self.layout.addWidget(self.second_set_of_instructions) + + self.save_preferences_button = QPushButton("Apply the Change") + self.save_preferences_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: green; color: yellow;") + self.save_preferences_button.clicked.connect( + self.implement_local_data_saving_change) + self.save_preferences_button.setVisible(False) + self.layout.addWidget(self.save_preferences_button) + + # return to main page button: + self.return_to_the_main_page_button = QPushButton( + "Nevermind. Return to Main Page") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: black;") + self.return_to_the_main_page_button.clicked.connect( + self.update_ui_to_return_to_the_main_page) + self.layout.addWidget(self.return_to_the_main_page_button) + + def show_the_apply_change_button(self): + self.first_set_of_instructions.setStyleSheet(self.lowkey_style_box) + self.second_set_of_instructions.setVisible(True) + self.save_preferences_button.setVisible(True) + + def implement_local_data_saving_change(self): + chosen_log_choice = self.local_data_preference_dropdown.currentText() + + if chosen_log_choice == "wipe codes": + update_config_with = False + else: + update_config_with = True + + # It's calling on a module to change the config JSON: + self.config_file_data = replace_config_value( + self.name_of_config_file, "local_data", update_config_with) + + # return back: + self.update_ui_to_return_to_the_main_page() + + def implement_email_disabled_change(self): + chosen_email_preference = self.email_preference_dropdown.currentText() + + list_of_email_preferences = ["yes, enable", "no, disable"] + + if chosen_email_preference == "no, disable": + turn_off_email_option = True + else: + turn_off_email_option = False + + # It's calling on a module to change the config JSON: + self.config_file_data = replace_config_value( + self.name_of_config_file, "turn_off_email_option", turn_off_email_option) + + # return back: + self.update_ui_to_return_to_the_main_page() + + def restore_previous_session(self): + # get a list of all the locally saved past orders: + past_orders_data = return_all_locally_saved_orders_for_the_current_profile() + + # setup a style for this page: + self.hipster_ecommerce_style = """ + QLabel { + font-size: 14px; + font-weight: bold; + color: #333; /* Dark gray for text */ + background-color: #f8f8f8; /* Light gray background */ + border: 2px solid #007BFF; /* Blue border */ + border-radius: 10px; /* Rounded corners */ + padding: 10px; /* Padding for a spacious look */ + margin: 5px; /* Margin to separate from other elements */ + } + QLabel:hover { + background-color: #e0e0e0; /* Slightly darker gray on hover */ + border-color: #0056b3; /* Darker blue border on hover */ + } + """ + + # error check if there are no past orders, or it's a new profile: + if past_orders_data == False: + self.clear_the_main_page_ui() + sorry_no_data_message = "I'm sorry, but there is no local SMS/proxy data for this profile. This could be a brand new profile, or an error with accessing your local log files." + sorry_no_data_label = QLabel(sorry_no_data_message) + sorry_no_data_label.setStyleSheet(self.hipster_ecommerce_style) + sorry_no_data_label.setWordWrap(True) + self.layout.addWidget(sorry_no_data_label) + else: + self.clear_the_main_page_ui() + + # inform them it's on their local PC: + self.local_computer_data_label = QLabel( + f"This is data on your local computer. Btw you can't restore a Session you didn't pay for yet.") + self.local_computer_data_label.setStyleSheet(self.active_style_box) + self.local_computer_data_label.setWordWrap(True) + self.layout.addWidget(self.local_computer_data_label) + + counter_of_how_many_rows = 0 + + # prep a grid layout to put them in: + self.grid_of_orders = QGridLayout() + + # Create labels and buttons for each order in the list: + for each_order in past_orders_data: + # prep data: + each_billing_id, each_service, each_complete_status = each_order + + # prep variables to display to the end user: + if each_complete_status == True: + display_status_to_user = "Completed" + else: + display_status_to_user = "Not yet Completed" + + message_to_display_for_each_billing_id = f"{each_billing_id} with {each_service}" + each_order_label = QLabel( + message_to_display_for_each_billing_id) + each_order_label.setStyleSheet(self.hipster_ecommerce_style) + each_order_label.setWordWrap(True) + self.grid_of_orders.addWidget( + each_order_label, counter_of_how_many_rows, 0) + + each_order_button = QPushButton(f"Restore {each_service}") + each_order_button.clicked.connect( + lambda checked, text=each_billing_id: self.restore_previous_session_via_button(text)) + each_order_button.setStyleSheet(""" + QPushButton { + font-size: 16px; + font-weight: bold; + color: white; /* White text */ + background-color: #28a745; /* Green background */ + border: none; /* No border */ + border-radius: 5px; /* Slightly rounded corners */ + padding: 12px 20px; /* Vertical and horizontal padding */ + } + QPushButton:hover { + background-color: #218838; /* Darker green on hover */ + } + QPushButton:pressed { + background-color: #1e7e34; /* Even darker green when pressed */ + } + """) + + self.grid_of_orders.addWidget( + each_order_button, counter_of_how_many_rows, 1) + + each_order_delete_button = QPushButton(f"Delete") + each_order_delete_button.clicked.connect( + lambda checked, text=each_billing_id: self.delete_a_previous_session(text)) + each_order_delete_button.setStyleSheet(""" + QPushButton { + font-size: 15px; + font-weight: bold; + color: white; /* White text */ + background-color: #FF0000; /* red background */ + border: none; /* No border */ + border-radius: 5px; /* Slightly rounded corners */ + padding: 12px 20px; /* Vertical and horizontal padding */ + } + QPushButton:hover { + background-color: #FF1000; /* Darker green on hover */ + } + QPushButton:pressed { + background-color: #1e7e34; /* Even darker green when pressed */ + } + """) + self.grid_of_orders.addWidget( + each_order_delete_button, counter_of_how_many_rows, 2) + + # this counter is for the grid layout: + counter_of_how_many_rows = counter_of_how_many_rows + 1 + + try: + self.layout.addLayout(self.grid_of_orders) + except: + print("no grid layout because it's an empty profile config.") + + # manually enter billing code button: + self.enter_manually_button = QPushButton( + "Or Manually Enter a Billing Code") + self.enter_manually_button.setStyleSheet(self.blue_chill_style) + self.enter_manually_button.clicked.connect( + self.manually_restore_previous_session) + self.layout.addWidget(self.enter_manually_button) + + # return to main page button: + self.return_to_the_main_page_button = QPushButton( + "Nevermind. Return to Main Page") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: black;") + self.return_to_the_main_page_button.clicked.connect( + self.update_ui_to_return_to_the_main_page) + self.layout.addWidget(self.return_to_the_main_page_button) + + def remove_grid_layout(self): + try: + # Remove the grid layout from the main layout + self.layout.removeItem(self.grid_of_orders) + + # Delete all widgets in the grid layout + for i in range(self.grid_of_orders.count()): + widget = self.grid_of_orders.itemAt(i).widget() + if widget: + widget.deleteLater() # Safely delete the widget + + # Delete the grid layout itself + del self.grid_of_orders + except: + print("no grid") + + def delete_a_previous_session(self, order): + delete_an_order(order) + self.update_ui_to_return_to_the_main_page() + + def restore_previous_session_via_button(self, order): + try: + # Call the method to remove the grid layout + self.remove_grid_layout() + except: + pass + + self.peer_to_peer_billing_id = order + self.restore_previous_session_function(self.peer_to_peer_billing_id) + + # start: restore previous section + def manually_restore_previous_session(self): + text, ok = QInputDialog.getText( + self, 'Restore Previous Session', 'Enter your billing ID:') + + if ok: # If the user clicked ok: + self.process_input(text) + + def process_input(self, input_text): + try: + # Call the method to remove the grid layout + self.remove_grid_layout() + except: + pass + + # Save the input text as a variable + self.input_variable = input_text + # Show the input in a message box + QMessageBox.information( + self, "Restore", f"You entered: {self.input_variable}") + + # save the input as the buyer billing id: + self.peer_to_peer_billing_id = self.input_variable + + # commented this out for the new options menu flow: + # remove the main button, since it's not being removed by the upcoming function as we return to normal flow: + # self.button.deleteLater() + + self.restore_previous_session_function(self.peer_to_peer_billing_id) + # end: restore previous section + + def on_right_item_clicked(self, item): + # We're filling in the locations that are available for that selected service on the right column/box: + selected_service = item.text() + + list_of_locations = get_the_locations_for_a_service( + self.initial_data, selected_service) + self.location_dropdown.clear() + + # Get Locally Saved Profile Data: + profile_location_and_proxy_tuple = get_profile_location_and_proxy_status_as_tuple() + + # Now we find out if it's a Pre-existing Profile + if profile_location_and_proxy_tuple == False: + # Since it's a new profile, we need to setup a location selection: + self.location_dropdown.addItems(list_of_locations) + # For a new profile, now that they selected a service from the right column, show the send button at bottom: + self.button.setVisible(True) + self.turn_off_email_option = search_key_in_json( + self.config_file_data, "turn_off_email_option", False) + if self.turn_off_email_option == True: + self.button.setText("Residential Proxy and SMS (€10)") + # they can also get only SMS for a new profile: + self.just_sms_button.setVisible(True) + self.label_for_profile_status.setText( + f"Based on your local data, this is a new profile, that has not yet been assigned a residential proxy") + else: + # Pre-existing profiles have a location already, so they don't need to pick: + profile_location, profile_proxy_status = profile_location_and_proxy_tuple + + # check if this service is available for the pre-existing profile location: + if profile_location in list_of_locations: + # display that location is available: + only_that_location_list = [profile_location] + self.location_dropdown.addItems(only_that_location_list) + # they can only buy SMS or email for this service, + self.just_sms_button.setVisible(True) + self.label_for_profile_status.setText( + f"Your locally saved data shows this profile has a proxy already for {profile_location}. But you can get more SMS numbers or emails. If you want to pick a new location, please make a new browser fingerprint profile.") + else: + self.label_for_profile_status.setText( + f"That service is not available for {profile_location}. Your locally saved data shows this profile has a proxy for {profile_location}") + + self.label_for_profile_status.setVisible(True) + + def on_item_clicked(self, item): + # Get the selected item's text + selected_item = item.text() + # Retrieve the corresponding list from the mapping + new_list = self.list_mapping.get(selected_item, []) + self.update_list_widget(new_list) + + def update_list_widget(self, new_list): + # this clears the existing items from the list and adds the new ones when the selection on the left changes: + self.list_widget2.clear() + self.list_widget2.addItems(new_list) + + @asyncSlot() + async def on_dispute_button_click(self): + asyncio.create_task(self.dispute_send_to_flask("dispute_new_seller")) + + @asyncSlot() + async def on_yes_button_click(self): + asyncio.create_task(self.dispute_send_to_flask("yes_worked")) + + @asyncSlot() + async def just_sms_no_proxy(self): + # this is for NO proxy: + self.proxy_status = False + + # Step 1: Run the async function + asyncio.create_task(self.button_pushed_send_to_flask()) + + # Step 2: Show dialog and hide button after a short delay + QTimer.singleShot(0, self.show_dialog_and_hide_button) + + @asyncSlot() # Decorator to allow this method to be async + async def on_button_click(self): + # this is for a PROXY: + self.proxy_status = True + + # Step 1: Run the async function + asyncio.create_task(self.button_pushed_send_to_flask()) + + # Step 2: Show dialog and hide button after a short delay + QTimer.singleShot(0, self.show_dialog_and_hide_button) + + def show_dialog_and_hide_button(self): + self.show_dialog() + try: + self.button.hide() + except: + pass + + try: + self.just_sms_button.hide() + except: + pass + + def show_dialog(self): + msg = QMessageBox() + msg.setText("Sent! Wait a few seconds") + msg.exec() + + +# Start: Send data to Flask Section: + + + async def button_pushed_send_to_flask(self): + + # get data from dropdowns to send to the API: + chosen_payment_method = self.payment_method_dropdown.currentText() + uppercase_chosen_location = self.location_dropdown.currentText() + chosen_location = uppercase_chosen_location.lower() + selected_items = self.list_widget2.selectedItems() + chosen_service_as_string = selected_items[0].text() + + # email section: + uppercase_chosen_email = self.email_dropdown.currentText() + self.chosen_email = filter_email_names(uppercase_chosen_email) + + # could uncomment for debug: + # print(f"This is the chosen service as a string: {chosen_service_as_string}") + + # Send this data to the Flask server: + returned_data = await send_data_to_flask(chosen_payment_method, chosen_location, chosen_service_as_string, self.chosen_email, self.proxy_status, self.peer_to_peer_billing_id) + print(f"this is data: {returned_data}") + # self.record_of_complete = True + + accepted_codes = [200, 201] + rejected_codes = [400, 401, 404] + + # We're checking if it returned an error or registered the user: + if 'message' in returned_data: + message = returned_data['message'] + + if message == "Registered" or message == "registered": + # It replied with crypto addresses, we're game on, + + # First, Reload the Config data because we want to see if the user doesn't want logs: + self.config_file_data = load_or_setup_config( + self.name_of_config_file) + + # We're checking if they want logs, and if they do we're now updating the Local Logs, to make or update the profile: + did_it_work = create_or_add_to_profile_config( + self.config_file_data, self.peer_to_peer_billing_id, chosen_location, self.proxy_status, chosen_service_as_string, self.chosen_email) + if did_it_work == "error": + print("Error with saving billing code to local log") + + # Update the GUI with the crypto addresses and begin process: + self.update_ui(returned_data) + else: + # Display Errors: + self.update_ui_for_errors(message) + # Display Connection Errors: + elif 'error' in returned_data: + connection_error_is = returned_data['error'] + self.update_ui_for_errors(connection_error_is) + else: + self.update_ui_for_errors(returned_data) + + return returned_data +# End: Send data to Flask Section + +# Start: DISPUTE Send data to Flask Section: + async def dispute_send_to_flask(self, how_did_it_go): + # Send this data to the Flask server + returned_data = await dispute_send_data_to_flask(how_did_it_go, self.peer_to_peer_billing_id) + filter_returned_data_message = returned_data.get('message') + # self.record_of_complete = True # not sure if I need this line anymore + + # Update the UI if the dispute was accepted or rejected. + # filter_returned_data_message is what the API returned + # how_did_it_go is how the user said it went. + if how_did_it_go == "dispute_new_seller": + if filter_returned_data_message == "dispute_accepted": + # Dispute accepted: + self.update_ui_for_dispute() + else: + # Dispute Rejected: + self.update_ui_for_dispute_rejected() + elif how_did_it_go == "yes_worked": + # NOT disputed, accepted: + self.update_ui_for_peaceful_finalized_acceptance() + + return returned_data +# End: DISPUTE send to Flask Section + + +# Start SECOND: Send data to Flask Section, CHECK PAYMENT. + + @asyncSlot() # Decorator to allow this method to be async + async def check_if_paid_on_timer(self): + # Step 1: Run the async function + asyncio.create_task(self.check_payment_button_pushed_send_to_flask()) + + # Step 2: Show dialog and hide button after a short delay + # QTimer.singleShot(0, self.show_dialog_and_hide_button) + + # def show_dialog_and_hide_button(self): + # self.show_dialog() + # self.button.hide() + + async def check_payment_button_pushed_send_to_flask(self): + # Send this data to the Flask server + returned_data = await check_if_paid_by_sending_data_to_flask(self.peer_to_peer_billing_id) + print(f"this is data: {returned_data}") + # self.record_of_complete = True + + # Update the GUI with the response on if it's paid and the SMS status: + self.update_ui_after_checking_if_paid(returned_data) + return returned_data + + def show_an_error(self, error_message): + msg = QMessageBox() + msg.setText(f"{error_message}") + msg.exec() + + def update_ui_after_checking_if_paid(self, returned_data): + try: + if isinstance(returned_data, dict): + # Directly use the dictionary + returned_data_as_a_dictionary = returned_data + else: + # If it's a string, format it and load it as a dictionary + valid_json_string = returned_data.replace("'", '"') + returned_data_as_a_dictionary = json.loads(valid_json_string) + + # Get the data from that: + self.payment_status_in_GUI = returned_data_as_a_dictionary.get( + 'payment_status') + self.code_status_in_GUI = returned_data_as_a_dictionary.get( + 'code_status') + + # this is used further down, and it's for also checking if it's in the restoration flow: + list_of_all_types_of_confirmed = ["confirmed", "restore_confirmed"] + + # if it's already given a code, move to next screen: + if self.code_status_in_GUI == "send_code_to_buyer": + # Stop checking if it's paid, we're past that if it's "send_code_to_buyer": + self.timer.stop() + # update UI to get code, and switch to code endpoint: + self.update_ui_after_to_get_code() + + elif self.code_status_in_GUI == "already_finalized": + # Stop checking if it's paid, we're past that if it's "send_code_to_buyer": + self.timer.stop() + # update UI to get code, and switch to code endpoint: + self.bring_trade_back_from_dead() + + # If it's fully paid, then we're giving the proxy info, so check if paid: + elif self.code_status_in_GUI == "rejected": + # Stop checking if it's paid: + self.timer.stop() + elif self.code_status_in_GUI == "First Seller has 10 minutes to confirm": + self.update_status_label.setStyleSheet(self.lowkey_style_box) + self.update_sms_status_label.setStyleSheet( + self.active_style_box) + + elif "refund_crypto" in returned_data_as_a_dictionary: + # this is triggered when we're doing a refund, + self.refund_crypto = returned_data_as_a_dictionary.get( + 'refund_crypto') + self.timer.stop() + + # get the refund crypto address with a text box, + self.refund_crypto_text_box = QLineEdit(self) + # Set the size policy to make the box bigger + self.refund_crypto_text_box.setMinimumSize(300, 40) + # Set the stylesheet for the grey background + self.refund_crypto_text_box.setStyleSheet( + "background-color: blue;") + self.refund_crypto_text_box.setPlaceholderText( + f"Enter your {self.refund_crypto} refund address") + self.layout.addWidget(self.refund_crypto_text_box) + + # button to submit crypto address: + self.button_to_submit_the_refund_address = QPushButton( + f"Submit {self.refund_crypto} Address") + self.button_to_submit_the_refund_address.setStyleSheet( + "font-size: 20px; padding: 30px; background-color: green; color: yellow;") + self.button_to_submit_the_refund_address.clicked.connect( + self.gui_calls_send_crypto_address_for_refund) + self.layout.addWidget(self.button_to_submit_the_refund_address) + + # If it's fully paid and confirmed, then we're moving on to the next section with giving the phone number: + elif self.payment_status_in_GUI == "paid" and self.code_status_in_GUI in list_of_all_types_of_confirmed: + # Get the phone number and set variable to display it: + self.assigned_phone_number_in_GUI = returned_data_as_a_dictionary.get( + 'assigned_phone_number') + + if self.code_status_in_GUI == "restore_confirmed": + self.display_code_status_in_GUI = f"The Seller is Ready to Restore. If you need the Phone number, then it's {self.assigned_phone_number_in_GUI}. Hit 'copy' to proceed." + else: + self.display_code_status_in_GUI = f"Step 1. Go sign-up for the service. Phone number is {self.assigned_phone_number_in_GUI}" + + # check if there's proxy data, and if so then process it: + if "proxy_ip_address" in returned_data_as_a_dictionary: + process_the_proxy(returned_data_as_a_dictionary) + else: + print("No Proxy") + + # Stop checking if it's paid & confirmed: + self.timer.stop() + + # check if there's email data, + if "full_email" in returned_data_as_a_dictionary: + self.full_email_in_GUI = returned_data_as_a_dictionary.get( + 'full_email') + self.email_password_in_GUI = returned_data_as_a_dictionary.get( + 'email_password') + self.email_url_in_GUI = returned_data_as_a_dictionary.get( + 'email_url') + self.email_operator_in_GUI = returned_data_as_a_dictionary.get( + 'email_operator_name') + self.display_code_status_in_GUI = f"Step 2. Phone number is {self.assigned_phone_number_in_GUI}" + # save it, + # if we recieved this email data in the same session as the initial order, then self.chosen_email has the operator + try: + did_it_create_config = setup_email_config( + self.email_operator_in_GUI, self.full_email_in_GUI, self.email_password_in_GUI, self.email_url_in_GUI) + print(f"did_it_create_config: {did_it_create_config}") + except: + print("Internal error with saving the email data") + else: + print("No Email") + self.full_email_in_GUI = None + + # Update the GUI for the whole next section on the phone number: + self.update_ui_after_getting_phone_number() + # end confirmed section + + # Start: PROCESS SECTION + # But if it's just processing, we can slow the timer during this: + elif self.payment_status_in_GUI == "processing": + self.timer.start(9000) + else: + print("checked, but it's not showing yet") + # self.sms_status_in_GUI = "Waiting on Payment" + + # Paid or Not, update the label: + try: + # if restore flow.. + if self.payment_status_in_GUI == "not_paid": + self.update_status_label.setText( + f"Payment Status: Not yet Paid. Please pay") + # self.update_status_label.styleSheet(self.active_style_box) + else: # normal flow: + self.update_status_label.setText( + f"Payment Status: {self.payment_status_in_GUI}") + except RuntimeError: + print( + "You're trying to change the text of a label, but it's already been deleted.") + + try: + # doing more restore flow here, this is because for the original flow the messages were server-side, for the restore flow I switched to client-side: + if self.code_status_in_GUI == "restore_confirmed": + self.update_sms_status_label.setText( + f"SMS Status: Seller for your specific restore number is ready.") + + try: + if self.the_returned_crypto_address_is: + pass + # Except should trigger if this guy is restoring, but lost his crypto address. + except: + # so stop checking if he paid: + self.timer.stop() + # and let him get a new address: + self.get_new_address_button = QPushButton( + "Get a New Address") + self.get_new_address_button.setStyleSheet( + "font-size: 15px; padding: 15px; background-color: green; color: yellow;") + self.get_new_address_button.clicked.connect( + self.yes_pay_to_restore_send) + self.layout.addWidget(self.get_new_address_button) + + else: # normal flow (non restore) + self.update_sms_status_label.setText( + f"SMS Status: {self.code_status_in_GUI}") + except RuntimeError: + print( + "You're trying to change the text of a label, but it's already been deleted.") + + except json.JSONDecodeError as e: + print(f"JSON decoding error: {e}") + # Stop checking if it can't format the JSON: + self.timer.stop() + return +# donkey cunt + except Exception as e: + exc_type, exc_value, exc_tb = sys.exc_info() + tb_summary = traceback.extract_tb(exc_tb) + # Get the line number of the error + line_number = tb_summary[-1].lineno + error_msg = f"An error on line {line_number} produced: {e}" + print(error_msg) + self.show_an_error(f"Error occurred: {e}") + # stop checking: + self.timer.stop() + + def update_ui_after_getting_phone_number(self): + + # first clear layouts: + try: + for i in reversed(range(self.grid_layout.count())): + item = self.grid_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + except: + print("No Grid layout") + + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Is there email data? + if self.full_email_in_GUI is not None: + # Label to display the email: + self.full_email_label = QLabel( + f"Step 1. Go sign-up for the service. Email is {self.full_email_in_GUI}") + self.full_email_label.setStyleSheet(self.active_style_box) + self.full_email_label.setWordWrap(True) + self.layout.addWidget(self.full_email_label) + + # Label to copy-paste the email url: + self.copy_email_url_button = QPushButton("Copy Email's URL") + self.copy_email_url_button.setStyleSheet( + "font-size: 15px; padding: 15px; background-color: green; color: yellow;") + self.copy_email_url_button.clicked.connect( + self.copy_email_url_function) + self.layout.addWidget(self.copy_email_url_button) + + # Label to copy-paste the email: + self.copy_full_email_button = QPushButton("Copy Email") + self.copy_full_email_button.setStyleSheet( + "font-size: 20px; padding: 15px; background-color: green; color: yellow;") + self.copy_full_email_button.clicked.connect( + self.copy_full_email_function) + self.layout.addWidget(self.copy_full_email_button) + + # Label to copy-paste the email password: + self.copy_email_password_button = QPushButton( + "Copy Email's Password") + self.copy_email_password_button.setStyleSheet( + "font-size: 20px; padding: 15px; background-color: green; color: yellow;") + self.copy_email_password_button.clicked.connect( + self.copy_email_password_function) + self.layout.addWidget(self.copy_email_password_button) + + # Label to display the phone number: + self.after_confirm_sms_status_label = QLabel( + f"{self.display_code_status_in_GUI}") + self.after_confirm_sms_status_label.setStyleSheet( + self.active_style_box) + self.after_confirm_sms_status_label.setWordWrap(True) + self.after_confirm_sms_status_label.setFixedWidth(800) + self.after_confirm_sms_status_label.setMaximumHeight(250) + self.layout.addWidget(self.after_confirm_sms_status_label) + + # Label to copy-paste the phone number: + # flag variable for the apperance of the button in copy_phone_number_function in the next step, which this button triggers + self.get_code_button_already_visible = False + self.copy_phone_number_button = QPushButton("Copy Phone Number") + self.copy_phone_number_button.setStyleSheet( + "font-size: 30px; padding: 15px; background-color: green; color: yellow;") + self.copy_phone_number_button.clicked.connect( + self.copy_phone_number_function) + self.layout.addWidget(self.copy_phone_number_button) + + # Label to display instructions: + self.label_for_instructions = QLabel( + f"After that service sends the SMS code to that number, THEN hit the button below.") + self.label_for_instructions.setStyleSheet(self.lowkey_style_box) + # self.label_for_instructions.setStyleSheet("font-size: 20px;") + self.label_for_instructions.setWordWrap(True) + self.label_for_instructions.setFixedWidth(800) + self.label_for_instructions.setMaximumHeight(300) + self.layout.addWidget(self.label_for_instructions) + self.label_for_instructions.setVisible(False) + + # Start: Display the Code Section + + @asyncSlot() # Decorator to allow this method to be async + async def with_slot_async_get_code_function(self): + # Step 1: Run the async function + asyncio.create_task(self.send_to_get_code_function()) + + async def send_to_get_code_function(self): + # Send this data to the Flask server + returned_data = await ready_for_code_by_sending_data_to_flask(self.peer_to_peer_billing_id) + + # DEBUG SECTION! uncomment to debug, + # print (f"this is data: {returned_data}") + # self.record_of_complete = True + + # Update the GUI with the response data + self.update_ui_after_checking_for_code(returned_data) + return returned_data + + def update_ui_after_checking_for_code(self, returned_data): + try: + if isinstance(returned_data, dict): + # Directly use the dictionary + returned_data_as_a_dictionary = returned_data + else: + # If it's a string, format it and load it as a dictionary + valid_json_string = returned_data.replace("'", '"') + returned_data_as_a_dictionary = json.loads(valid_json_string) + + # Get the data from that: + self.code_status_in_GUI = returned_data_as_a_dictionary.get( + 'code_status') + self.code_in_GUI = returned_data_as_a_dictionary.get( + 'assigned_code') + + if self.code_in_GUI is None: + self.code_in_GUI = "Please wait" + elif self.code_status_in_GUI == "timed_out_buyer": + # stop timer to check for code and display the "code" which is just telling them they took too long: + self.get_code_timer.stop() + self.after_requesting_code_label.setText( + f"Please close this window and try again. {self.code_in_GUI}") + # else triggered means they got a code. They weren't timed out and it isn't still waiting + else: + if self.label_for_instructions.styleSheet() == self.active_style_box: + pass + else: + self.after_requesting_code_label.setStyleSheet( + self.active_style_box) + + # this was the original way of doing it, prior to the upgrade of universal styles in the __init__ + # self.after_requesting_code_label.setStyleSheet("font-size: 50px;") + # self.label_for_instructions.setStyleSheet("font-size: 50px;") + + # print it out for debug status: + print(self.code_status_in_GUI) + print(self.code_in_GUI) + + # display code in GUI: + if self.code_in_GUI == "Please wait": + self.after_requesting_code_label.setText( + f"Contacting Seller to Fetch the Code. Make sure you told the website to send it.") + self.after_requesting_code_label.setStyleSheet( + self.active_style_box) + else: + self.after_requesting_code_label.setText( + f"Code: {self.code_in_GUI}") + self.copy_paste_code.setVisible(True) + + # stop timer to check: + self.get_code_timer.stop() + except: + print("No code yet") + + def update_ui_after_to_get_code(self): + + # first clear layouts: + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # We're doing a 2 second timer to check if the code is ready from API: + self.timer = QTimer() + self.timer.timeout.connect(self.with_slot_async_get_code_function) + self.timer.start(2000) + + # Label to display the code: + self.code_in_GUI = "Getting Seller's Reply..." + self.after_requesting_code_label = QLabel(f"{self.code_in_GUI}") + self.after_requesting_code_label.setStyleSheet( + "background-color: white; color: black; font-size: 30px;") + self.after_requesting_code_label.setWordWrap(True) + self.after_requesting_code_label.setFixedWidth(800) + self.after_requesting_code_label.setMaximumHeight(250) + self.layout.addWidget(self.after_requesting_code_label) + + # button to copy-paste the code: + self.copy_paste_code = QPushButton("Copy Code") + self.copy_paste_code.setStyleSheet( + "font-size: 30px; padding: 15px; background-color: green; color: yellow;") + self.copy_paste_code.clicked.connect(self.copy_code_function) + self.layout.addWidget(self.copy_paste_code) + self.copy_paste_code.setVisible(False) + + # Label to display instructions: + self.label_for_instructions = QLabel(f"Did this work?") + self.label_for_instructions.setStyleSheet(self.lowkey_style_box) + self.label_for_instructions.setWordWrap(True) + self.label_for_instructions.setFixedWidth(800) + self.label_for_instructions.setMaximumHeight(200) + self.layout.addWidget(self.label_for_instructions) + +# End: Display the Code Section + + +# Start: Display the Error Section: + + + def update_ui_for_errors(self, returned_data_as_dict): + returned_data = str(returned_data_as_dict) + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Clear all widgets from the horizontal layout + for i in reversed(range(self.h_layout.count())): + item = self.h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + for i in reversed(range(self.top_ribbon_h_layout.count())): + item = self.top_ribbon_h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Display the header label for the Error page (with the label style declared in the init section) + label_for_peer_to_peer_billing_id = QLabel( + f"Error! Something went wrong") + label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style) + label_for_peer_to_peer_billing_id.setSizePolicy( + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + self.layout.addWidget(label_for_peer_to_peer_billing_id) + + # This label gives the raw error message in a box: + self.update_status_label = QLabel(returned_data) + self.update_status_label.setStyleSheet( + "background-color: white; color: black; font-size: 25px;") + self.update_status_label.setWordWrap(True) + self.update_status_label.setFixedWidth(700) + self.update_status_label.setMaximumHeight(400) + self.layout.addWidget(self.update_status_label) + + +# Start: Display the Result Section: + + # We're displaying the crypto payment data and SMS status windows: + + + def update_ui(self, returned_data): + self.the_returned_crypto_address_is = returned_data.get('address') + self.the_returned_crypto_amount_is = returned_data.get('amount_owed') + + # Clear the layout and display the new label with the data + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Clear all widgets from the horizontal layout + for i in reversed(range(self.h_layout.count())): + item = self.h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + for i in reversed(range(self.top_ribbon_h_layout.count())): + item = self.top_ribbon_h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Display the ID: + label_for_peer_to_peer_billing_id = QLabel( + f"Your P2P ID: {self.peer_to_peer_billing_id}") + label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style) + label_for_peer_to_peer_billing_id.setWordWrap(True) + label_for_peer_to_peer_billing_id.setSizePolicy( + # Expanding vertical size policy + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + self.layout.addWidget(label_for_peer_to_peer_billing_id) + + # Create a button to Copy Paste ID: + self.copy_amount_button = QPushButton("Copy Your Billing ID") + # Set background and text color self.button.clicked.connect(self.show_selected) + self.copy_amount_button.setStyleSheet( + "font-size: 20px; padding: 20px; background-color: green; color: yellow;") + self.copy_amount_button.clicked.connect(self.copy_billing_id_function) + self.layout.addWidget(self.copy_amount_button) + + # Create new labels with the response data + crypto_long_address_as_string = str( + self.the_returned_crypto_address_is) + length_of_long_address = len(crypto_long_address_as_string) + + # Litecoin is 43, so let's see if it's long enough for one line, if so break it up: + if length_of_long_address >= 44: + break_into_three = length_of_long_address / 2 + import math + round_up_breaking_into_three_groups = math.ceil(break_into_three) + first_group = crypto_long_address_as_string[0: + round_up_breaking_into_three_groups] + second_group = crypto_long_address_as_string[ + round_up_breaking_into_three_groups:length_of_long_address] + else: + # probably litecoin, so one line: + first_group = crypto_long_address_as_string + second_group = "" + + # Create a QGridLayout + self.grid_layout = QGridLayout() + + # This next section creates four widgets to add to the grid layout for the crypto data and copy buttons, + + # Address Label: + self.address_label = QLabel(f"{first_group}\n{second_group}") + self.address_label.setWordWrap(True) + self.address_label.setFixedWidth(600) + self.address_label.setMaximumHeight(100) + self.address_label.setStyleSheet( + "background-color: grey; color: black; font-size: 15px;") + self.layout.addWidget(self.address_label) + + # Create a button to Copy Paste Address + self.copy_crypto_address_button = QPushButton("Copy Address") + self.copy_crypto_address_button.setStyleSheet( + # Set background and text color + "font-size: 30px; padding: 15px; background-color: green; color: yellow;") + self.copy_crypto_address_button.clicked.connect( + self.copy_crypto_address_function) + self.layout.addWidget(self.copy_crypto_address_button) + + # Amount label: + self.amount_label = QLabel(str(self.the_returned_crypto_amount_is)) + self.amount_label.setStyleSheet( + "background-color: grey; color: black; font-size: 20px;") + self.amount_label.setFixedWidth(600) + self.amount_label.setMaximumHeight(100) + self.layout.addWidget(self.amount_label) + + # Create a button to Copy Paste Amount + self.copy_amount_button = QPushButton("Copy Amount") + # Set background and text color self.button.clicked.connect(self.show_selected) + self.copy_amount_button.setStyleSheet( + "font-size: 30px; padding: 30px; background-color: green; color: yellow;") + self.copy_amount_button.clicked.connect(self.copy_amount_function) + self.layout.addWidget(self.copy_amount_button) + + # Add widgets to the grid layout + self.grid_layout.addWidget(self.address_label, 0, 0) # Row 0, Column 0 + self.grid_layout.addWidget( + self.copy_crypto_address_button, 0, 1) # Row 0, Column 1 + self.grid_layout.addWidget(self.amount_label, 1, 0) # Row 1, Column 0 + self.grid_layout.addWidget( + self.copy_amount_button, 1, 1) # Row 1, Column 1 + + # Add the grid layout to the main layout + self.layout.addLayout(self.grid_layout) + + # Payment check label: + self.update_status_label = QLabel("Payment Checker: Connecting..") + self.update_status_label.setStyleSheet(self.active_style_box) + self.update_status_label.setWordWrap(True) + self.update_status_label.setFixedWidth(800) + self.update_status_label.setMaximumHeight(120) + self.layout.addWidget(self.update_status_label) + + # SMS status label: + self.update_sms_status_label = QLabel("SMS Status: Connecting..") + self.update_sms_status_label.setStyleSheet(self.lowkey_style_box) + self.update_sms_status_label.setWordWrap(True) + self.update_sms_status_label.setFixedWidth(800) + self.update_sms_status_label.setMaximumHeight(250) + self.layout.addWidget(self.update_sms_status_label) + + # Create a timer + self.timer = QTimer() + self.timer.timeout.connect(self.check_if_paid_on_timer) + self.timer.start(5000) # Start the timer with a 5-second interval + + def restore_previous_session_function(self, buyer_billing_id_entered): + # Clear the layout and display the new label with the data + try: + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Clear all widgets from the horizontal layout + for i in reversed(range(self.h_layout.count())): + item = self.h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + for i in reversed(range(self.top_ribbon_h_layout.count())): + item = self.top_ribbon_h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + except: + pass + finally: + # Payment check label: + self.update_status_label = QLabel("Payment Checker: Connecting..") + self.update_status_label.setStyleSheet( + "background-color: white; color: black; font-size: 30px;") + self.update_status_label.setFixedWidth(700) + self.update_status_label.setMaximumHeight(100) + self.layout.addWidget(self.update_status_label) + + # Amount label: + self.update_sms_status_label = QLabel("SMS Status: Connecting..") + self.update_sms_status_label.setStyleSheet( + "background-color: white; color: black; font-size: 30px;") + self.update_sms_status_label.setWordWrap(True) + self.update_sms_status_label.setFixedWidth(800) + self.update_sms_status_label.setMaximumHeight(250) + self.layout.addWidget(self.update_sms_status_label) + + # Create a timer + self.timer = QTimer() + self.timer.timeout.connect(self.check_if_paid_on_timer) + self.timer.start(5000) # Start the timer with a 5-second interval + + def copy_crypto_address_function(self): + clipboard = QApplication.clipboard() + clipboard.setText(self.the_returned_crypto_address_is) + + def copy_amount_function(self): + clipboard = QApplication.clipboard() + clipboard.setText(self.the_returned_crypto_amount_is) + + def copy_billing_id_function(self): + clipboard = QApplication.clipboard() + clipboard.setText(self.peer_to_peer_billing_id) + + def copy_code_function(self): + clipboard = QApplication.clipboard() + clipboard.setText(self.code_in_GUI) + + if self.code_in_GUI is not None: + self.after_requesting_code_label.setStyleSheet( + self.lowkey_style_box) + self.label_for_instructions.setStyleSheet(self.active_style_box) + + # Yes Button: + self.yes_button = QPushButton("Yes") + self.yes_button.setStyleSheet( + "font-size: 30px; padding: 15px; background-color: green; color: yellow;") + self.yes_button.clicked.connect(self.on_yes_button_click) + self.layout.addWidget(self.yes_button) + + # No Button: + self.no_button = QPushButton("No, try a NEW seller & number") + self.no_button.setStyleSheet( + "font-size: 15px; padding: 15px; background-color: red; color: black;") + self.no_button.clicked.connect(self.on_dispute_button_click) + self.layout.addWidget(self.no_button) + + def hide_crypto_address_grid_layout(self): + for i in range(self.grid_layout.count()): + widget = self.grid_layout.itemAt(i).widget() + if widget is not None: + widget.hide() + + def copy_full_email_function(self): + clipboard = QApplication.clipboard() + clipboard.setText(self.full_email_in_GUI) + + def copy_email_password_function(self): + clipboard = QApplication.clipboard() + clipboard.setText(self.email_password_in_GUI) + try: + self.full_email_label.setStyleSheet(self.lowkey_style_box) + except: + pass + + def copy_email_url_function(self): + clipboard = QApplication.clipboard() + clipboard.setText(self.email_url_in_GUI) + + def copy_phone_number_function(self): + clipboard = QApplication.clipboard() + clipboard.setText(self.assigned_phone_number_in_GUI) + self.after_confirm_sms_status_label.setStyleSheet( + self.lowkey_style_box) + self.label_for_instructions.setStyleSheet(self.active_style_box) + self.label_for_instructions.setVisible(True) + try: + self.full_email_label.setVisible(False) + except: + pass + + # only add this button if it isn't already visible or added: + if self.get_code_button_already_visible == False: + self.ready_to_get_code_button = QPushButton("Step 3. Get the Code") + self.ready_to_get_code_button.setStyleSheet( + "font-size: 30px; padding: 15px; background-color: green; color: yellow;") + self.ready_to_get_code_button.clicked.connect( + self.update_ui_after_to_get_code) + self.layout.addWidget(self.ready_to_get_code_button) + self.get_code_button_already_visible = True + +# End: Display the Result Section + + +# Start: Dispute display UI + +# Start: Dispute ACCEPTED Display the Result Section: + + def update_ui_for_dispute(self): + # Clear the layout and display the new label with the data + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Clear all widgets from the horizontal layout + for i in reversed(range(self.h_layout.count())): + item = self.h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Display the ID: + label_for_peer_to_peer_billing_id = QLabel( + f"Dispute! Matching you with a New Number. {self.peer_to_peer_billing_id}") + label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style) + label_for_peer_to_peer_billing_id.setWordWrap(True) + label_for_peer_to_peer_billing_id.setSizePolicy( + # Expanding vertical size policy + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + self.layout.addWidget(label_for_peer_to_peer_billing_id) + + # Create a button to Copy Paste ID: + self.copy_amount_button = QPushButton("Copy Your Billing ID") + # Set background and text color self.button.clicked.connect(self.show_selected) + self.copy_amount_button.setStyleSheet( + "font-size: 20px; padding: 20px; background-color: green; color: yellow;") + self.copy_amount_button.clicked.connect(self.copy_billing_id_function) + self.layout.addWidget(self.copy_amount_button) + + # Payment check label: + self.update_status_label = QLabel("Payment Paid") + self.update_status_label.setStyleSheet( + "background-color: white; color: black; font-size: 30px;") + self.update_status_label.setFixedWidth(700) + self.update_status_label.setMaximumHeight(100) + self.layout.addWidget(self.update_status_label) + + # Status label: + self.update_sms_status_label = QLabel("SMS Status: Connecting..") + self.update_sms_status_label.setStyleSheet( + "background-color: white; color: black; font-size: 30px;") + self.update_sms_status_label.setWordWrap(True) + self.update_sms_status_label.setFixedWidth(800) + self.update_sms_status_label.setMaximumHeight(250) + self.layout.addWidget(self.update_sms_status_label) + + # Create a timer + self.timer = QTimer() + self.timer.timeout.connect(self.check_if_paid_on_timer) + self.timer.start(5000) # Start the timer with a 5-second interval + +# End dispute Accepted UI GUI + + +# Start: Dispute REJECED UI GUI + + + def update_ui_for_dispute_rejected(self): + # Clear the layout and display the new label with the data + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Clear all widgets from the horizontal layout + for i in reversed(range(self.h_layout.count())): + item = self.h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Display the ID: + label_for_peer_to_peer_billing_id = QLabel( + f"Any billing issue? Your P2P ID is: {self.peer_to_peer_billing_id}") + label_for_peer_to_peer_billing_id.setWordWrap(True) + label_for_peer_to_peer_billing_id.setStyleSheet(self.label_style) + label_for_peer_to_peer_billing_id.setSizePolicy( + # Expanding vertical size policy + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + self.layout.addWidget(label_for_peer_to_peer_billing_id) + + # Create a button to Copy Paste ID: + self.copy_amount_button = QPushButton("Copy Your Billing ID") + # Set background and text color self.button.clicked.connect(self.show_selected) + self.copy_amount_button.setStyleSheet( + "font-size: 20px; padding: 20px; background-color: green; color: yellow;") + self.copy_amount_button.clicked.connect(self.copy_billing_id_function) + self.layout.addWidget(self.copy_amount_button) + + # Status label: + self.update_sms_status_label = QLabel( + "I am so sorry to inform you that the automated system rejected your dispute. It's possible this is a technical error, please contact customer support with your Billing ID") + self.update_sms_status_label.setStyleSheet( + "background-color: white; color: black; font-size: 20px;") + self.update_sms_status_label.setWordWrap(True) + self.update_sms_status_label.setFixedWidth(800) + self.update_sms_status_label.setMaximumHeight(250) + self.layout.addWidget(self.update_sms_status_label) +# End: Dispute REJECED UI GUI + + +# Start: Zero Dispute. Finalize & End Peacefully. No Dispute. UI GUI + + + def update_ui_for_peaceful_finalized_acceptance(self): + # Clear the layout and display the new label with the data + + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Clear all widgets from the horizontal layout + for i in reversed(range(self.h_layout.count())): + item = self.h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Status label: + self.update_sms_status_label = QLabel( + "Thank you! This is complete. You can close the window.") + self.update_sms_status_label.setStyleSheet(self.active_style_box) + self.update_sms_status_label.setWordWrap(True) + self.update_sms_status_label.setFixedWidth(800) + self.update_sms_status_label.setMaximumHeight(250) + self.layout.addWidget(self.update_sms_status_label) +# End: Zero Dispute. Finalize & End Peacefully. No Dispute. UI GUI + + +# Start: Send REFUND CRYPTO address & Display result: + + + @asyncSlot() + async def gui_calls_send_crypto_address_for_refund(self): + self.timer.stop() + + # Step 1: Run the async function + asyncio.create_task( + self.async_gui_calls_send_crypto_address_for_refund()) + + async def async_gui_calls_send_crypto_address_for_refund(self): + # Send this data to the Flask server + returned_data = await send_crypto_address_for_refund(self.peer_to_peer_billing_id, self.refund_crypto_text_box.text()) + + # DEBUG SECTION! uncomment to debug, + print(f"this is data: {returned_data}") + + # Update the GUI with the response data + self.update_ui_after_sending_crypto_address(returned_data) + return returned_data + +# Start: Display the Error Section: + def update_ui_after_sending_crypto_address(self, returned_data): + # Clear all widgets from the vertical layout + for i in reversed(range(self.layout.count())): + item = self.layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # Clear all widgets from the horizontal layout + for i in reversed(range(self.h_layout.count())): + item = self.h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + for i in reversed(range(self.top_ribbon_h_layout.count())): + item = self.top_ribbon_h_layout.itemAt(i) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + # This label gives the raw error message in a box: + self.update_status_label = QLabel(str(returned_data)) + self.update_status_label.setStyleSheet( + "background-color: white; color: black; font-size: 25px;") + self.update_status_label.setWordWrap(True) + self.update_status_label.setFixedWidth(700) + self.update_status_label.setMaximumHeight(400) + self.layout.addWidget(self.update_status_label) +# End: Send REFUND CRYPTO address & Display result + + def bring_trade_back_from_dead(self): + self.clear_the_main_page_ui() + + message_for_user = f"The trade for {self.peer_to_peer_billing_id} is already finalized. Do you wish to pay 5 euros to restore it and get another code from the same service with the same number?" + self.label_for_api_fetch = QLabel(f"{message_for_user}") + self.label_for_api_fetch.setStyleSheet(self.active_style_box) + self.label_for_api_fetch.setWordWrap(True) + self.layout.addWidget(self.label_for_api_fetch) + + # yes pay: + self.yes_restore_dead_session_button = QPushButton( + "Yes, Pay 5 Euros to Restore") + self.yes_restore_dead_session_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: green; color: yellow;") + self.yes_restore_dead_session_button.clicked.connect( + self.yes_pay_to_restore_send) + self.layout.addWidget(self.yes_restore_dead_session_button) + + # return to main page button: + self.return_to_the_main_page_button = QPushButton( + "Nevermind. Return to Main Page") + self.return_to_the_main_page_button.setStyleSheet( + "font-size: 30px; padding: 10px; background-color: red; color: black;") + self.return_to_the_main_page_button.clicked.connect( + self.update_ui_to_return_to_the_main_page) + self.layout.addWidget(self.return_to_the_main_page_button) + + @asyncSlot() # Decorator to allow this method to be async + async def yes_pay_to_restore_send(self): + # Step 1: Run the async function + asyncio.create_task(self.restore_dead_trade_by_sending_to_flask()) + + # Step 2: Show dialog and hide button after a short delay + QTimer.singleShot(0, self.hide_restore_buttons) + + # This button hides elements while being sent to the server, but these elements may already be hidden. + def hide_restore_buttons(self): + self.show_dialog() + # this is the regular restore flow: + try: + self.yes_restore_dead_session_button.setVisible(False) + self.return_to_the_main_page_button.setVisible(False) + self.label_for_api_fetch.setText( + "Please hold while we contact that SMS seller.") + except: + # objects have been deleted already: + pass + + # this is the "lost address restore flow" + try: + self.get_new_address_button.setVisible(False) + except: + # objects have been deleted already: + pass + + +# Start: RESTORE Send data to Flask Section + # THIS IS STEP 1 OF RESTORE + + + async def restore_dead_trade_by_sending_to_flask(self): + # Send this data to the Flask server: + returned_data = await restore_an_already_finalized_number(self.peer_to_peer_billing_id, "restore") + print(f"this is data: {returned_data}") + are_we_checking_again = True + + # We're checking if it returned an error or registered the user: + if 'code_status' in returned_data: + code_status = returned_data.get('code_status') + if code_status == "restore_requested" or code_status == "restore_initiated": + display_message_for_user = "Contacting the Seller to request a restoration, please remain patient. If the seller is busy with another buyer or asleep in their timezone, it may temporarily reject you. If so, then try again." + elif code_status == "restore_but_seller_busy": + display_message_for_user = "The Seller is busy. It might be sleeping time in his/her timezone, vacation time, or they are on a different gig. Please try back later." + are_we_checking_again = False + elif code_status == "restore_confirmed": + display_message_for_user = "Seller confirmed, one moment please, as you must pay" + else: + display_message_for_user = "One moment please" + + try: + self.label_for_api_fetch.setText(f"{display_message_for_user}") + except: # incase it does not exist: + self.label_for_api_fetch = QLabel( + f"{display_message_for_user}") + self.label_for_api_fetch.setStyleSheet(self.active_style_box) + self.label_for_api_fetch.setWordWrap(True) + self.layout.addWidget(self.label_for_api_fetch) + + if are_we_checking_again == True: + # We're doing a 5 second timer to check if the seller is ready: + self.timer = QTimer() + self.timer.timeout.connect( + self.step_two_of_restore_get_confirm) + self.timer.start(5000) + # Display Connection Errors: + elif 'error' in returned_data: + connection_error_is = returned_data['error'] + self.update_ui_for_errors(connection_error_is) + elif 'message' in returned_data: + # Display Errors: + message = returned_data['message'] + self.update_ui_for_errors(message) + else: + self.update_ui_for_errors(returned_data) + + # Here we're on a repeat timer, checking the /restore endpoint if the guy is confirmed ready. + @asyncSlot() + async def step_two_of_restore_get_confirm(self): + # Step 1: Run the async function + asyncio.create_task( + self.on_timer_step_two_of_restore_dead_trade_by_sending_to_flask()) + + # THIS IS STEP 2 OF RESTORE + async def on_timer_step_two_of_restore_dead_trade_by_sending_to_flask(self): + # Send this data to the Flask server: + returned_data = await restore_an_already_finalized_number(self.peer_to_peer_billing_id, "is_restore_seller_ready") + print(returned_data) + if 'address' in returned_data: + print("We got an address") + # now this "restore flow" rejoins the main flow for new orders: + self.update_ui(returned_data) + elif 'code_status' in returned_data: + code_status = returned_data.get('code_status') + if code_status == "restore_confirmed": + self.timer.stop() + # We're now getting a crypto address: + self.get_restore_crypto_address() + elif code_status == "restore_but_seller_busy": + self.timer.stop() + display_message_for_user = "The Seller is busy. It might be sleeping time in his/her timezone, vacation time, or they are on a different gig. Please try back later." + self.label_for_api_fetch.setText(f"{display_message_for_user}") + # return to main page button: + self.return_to_the_main_page_button.setText( + "Fine. Return to Main Page") + self.return_to_the_main_page_button.setVisible(True) + + # Display Connection Errors: + elif 'error' in returned_data: + connection_error_is = returned_data['error'] + self.update_ui_for_errors(connection_error_is) + elif 'message' in returned_data: + message = returned_data['message'] + # Display Errors: + self.update_ui_for_errors(message) + else: + returned_data_as_string = str(returned_data) + self.update_ui_for_errors(returned_data_as_string) + + return returned_data +# End: RESTORE Send data to Flask Section + + @asyncSlot() # Decorator to allow this method to be async + async def get_restore_crypto_address(self): + # Step 1: Run the async function + asyncio.create_task(self.get_crypto_addy_for_restore()) + + async def get_crypto_addy_for_restore(self): + # Send this data to the Flask server + returned_data = await restore_an_already_finalized_number(self.peer_to_peer_billing_id, "is_restore_seller_ready") + print(f"returned_data: {returned_data}") + + if 'address' in returned_data: + print("We got an address") + # now this "restore flow" rejoins the main flow for new orders: + self.update_ui(self, returned_data) + else: + print("Error, we did not get a crypto address") + + # this may not be needed + return returned_data + + +''' + def update_ui_to_pay_for_restore(self): + payment_address = returned_data_as_a_dictionary.get('address') + display_address = f"We got a payment_address: {payment_address}" + print(f"{display_address}") + self.label_for_api_fetch.setText(f"{display_address}") + # We're doing a 5 second timer to check if the code is ready from API: + self.timer = QTimer() + self.timer.timeout.connect(self.check_if_seller_paid_for_a_restore) + self.timer.start(5000) + + @asyncSlot() # Decorator to allow this method to be async + async def check_if_seller_paid_for_a_restore(self): + # Step 1: Run the async function + asyncio.create_task(self.check_if_seller_paid_for_a_restore_function()) + + async def check_if_seller_paid_for_a_restore_function(self): + # Send this data to the Flask server + returned_data = await restore_an_already_finalized_number(self.peer_to_peer_billing_id, "is_restore_seller_ready") + + # Update the GUI with the response data + print(f"returned_data: {returned_data}") + return returned_data +''' + +if __name__ == "__main__": + app = QApplication(sys.argv) + + # async loop for app so that it can fetch the API while it displays the intro text. Then go right into doing network calls with GUI changes, + loop = QEventLoop(app) + asyncio.set_event_loop(loop) + + my_app = BuyerPeerPeerGUI() + my_app.show() + + with loop: + sys.exit(loop.run_forever()) diff --git a/SMS-Exchange-Linux-GUI/README.md b/SMS-Exchange-Linux-GUI/README.md new file mode 100755 index 0000000..890cf24 --- /dev/null +++ b/SMS-Exchange-Linux-GUI/README.md @@ -0,0 +1,21 @@ +# Step 1. clone it. +```bash +git clone https://git.simplifiedprivacy.com/Support/SMS-Exchange-Linux-GUI.git +``` +
+ +# Step 2. Setup venv +```bash +python3 -m venv venv +source venv/bin/activate +``` + +# Step 3. Install Prereqs +```bash +pip install -r requirements.txt +``` + +# Step 4. Run it +```bash +python3 GUI.py +``` diff --git a/SMS-Exchange-Linux-GUI/SCOPE.md b/SMS-Exchange-Linux-GUI/SCOPE.md new file mode 100755 index 0000000..9547849 --- /dev/null +++ b/SMS-Exchange-Linux-GUI/SCOPE.md @@ -0,0 +1,17 @@ +# Scope + +## Add with Button +To the Left of Enable + +# Process Proxy: +Inside 'interact_with_rest_of_app' folder +Placing that proxy.json in the correct format in the correct profile folder. + +## Which Profile Used: +Inside 'interact_with_rest_of_app' folder +Using Core to Return which Profile the User has Up + +## Enable button Enables Proxy.json +Possible stack with Tor, or pre-existing Wireguard + + diff --git a/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_and_save_json_from_our_api.cpython-311.pyc b/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_and_save_json_from_our_api.cpython-311.pyc new file mode 100755 index 0000000000000000000000000000000000000000..08a68995b49a38bead13e46b78ecd699a4c72a9f GIT binary patch literal 2320 zcmahLOKcNIbk@5YZ(=)k;(*$wltolv2jV3`ND(4Q1LRjEn&KdmTvm&B5-+iL-Pv)R zLbt&~fF3Jx4OLg7GfYvhBqQcqQ+=9Y>|jX3qq*d`w$I{Ws`n>X)2 z^VYr>iL@XXzua4}#+wlOlPww}P$yoU1mX@dktyWR44VTvAs?6t$lF|lKy_}T%*cJRm5xaDFF@p=#a%?|1Y2~p~q<-{*W7{~xn8SoP#BUy( zoSfifMyR`H6NH7ng!k1A2hss?M?7>?bXV9v+BCbh|_0Ab=%8m71i0Z+c$e=|0 z*&UmJ?9frvgIuW;SQMvGNf6L9WGNsTY1l!?Y<|mDOM17&u55lpKL_5@2=C07Nu<$H zL|eDLe2hqZkKf2%E7Qn~falmdwOaSlY6Y$KU0O$0rCm8jSEPO8uJbbi@Qqfbn^L+y zmjv3e$D+K;Vr)g;*J7PtwuLJ8GQA=!3$xi?E`!9A;Kj(y!Rh?#P&d?9De zTG%WQYr)7YrEE+!%eJUx?V4}Afc3`jfPA5}EEnl)cOPsk*v>en zWzQ|g)5Zce)lbu(T~=p_lUIi(#{H&}L*}u$d}ze5aBMxaX;&8obg)HF3{(FHk^sih{t1gSNq%HlLtXvma0k;8@y z4#<*f%o&!g<_wBSYI$@!icGC%SwJifm-~OCnaSeJyt?ERiE7!P3dK?D8qnpbJ29!kVL)x$ljCPThbU%0+Fhp8WOd3HJ!6#J4> zz_u@!h(%#R@gntQI4heH)~$q{4q;yu!kRhRS%Gb@Es%LN&CBC7N|?tlYv5<2NQ!@&d&TDD#FQoxOOeVD%fWW9#hF z=umPUL{o(&|D$({kV6nStA+b7e3|}&=N78A4BWb~DIJo>g!Opm_vhBc`=5JptsK`X zaqSyrvk8SeDxt$`r(cGSd7)$X6P2!kCr4j)4SQX~>um>aJ8SNvYhGJ_xvjs_*1w5_ zNY|5&YOLc<%Xck5^!?OdjwLIxq!&wWim=7^Ir^JP{=?8VZ$D~lYimFDdbrJNKVA+e zD&d3|PE_NaxBED6>`|i9JL0vE0hGhzmGHP19(Q>LoXDUZW?sDlajZX+&v zYAx%vo&qQ_ZU9h%y8o1MM-=%AOQVbiZI-E@M5?4{5a=y%fLwnNfdnf@kY<4 zaO1Cl%X@HdU$X1@D|!VOkq-gAR?g)evzWsJ^gsX3ZS(*D literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_and_save_json_from_our_api.cpython-312.pyc b/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_and_save_json_from_our_api.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..ca6b36b2f92121441775a14a684932fd949847de GIT binary patch literal 2007 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 F{TEJ~X@>v+ literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_initial_email_data.cpython-312.pyc b/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/get_initial_email_data.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..e8c10224e275d251ab61495ea806e34dc0670d65 GIT binary patch literal 1997 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 WgyLOg;D6>;oBPk literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/send_data_to_flask.cpython-312.pyc b/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/send_data_to_flask.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..2f2efdb85cf40e60b704f2646f6071ec5a7a4091 GIT binary patch literal 10271 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 H{V@3dA;s_G literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/should_api_be_triggered.cpython-311.pyc b/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/should_api_be_triggered.cpython-311.pyc new file mode 100755 index 0000000000000000000000000000000000000000..0ead4395f112bcef0a1e89bb2a0f674fe039984c GIT binary patch literal 842 zcmZ`%&ubGw6n?Xt=%zoCRxPEv*nnOFZMS$ShzeS)w;~h|&B0}xnKTCR>U{VH}A*yX1*Eb!{A^apk?=; zxxWd(PZe}cJ9ADUO9og;U3Q@&#cVG9Yp7 zS{2Xg*!zn;-6S+%2N}CP*19Gy_li(e`zE%7xO?UUtm_TEp{?SL8stUNy8yR98a)Es z262^u>_5*?^7lyu7J+IDumUgjMOYyPeSS4J=XxyfbD1ym$fr|tg-fx2kl5 z8Yo3VFkdE7s2((rcKXJu@EWtCkO}K)T~@en1$TnU039~zN3|s;Lc8QK$7j@f6xErq zXFXT#Q|7`>Xm*EY3Fgpxl8yq8JJfOl*G8#KI3=aS3M)MFsIAgV%$CAkUS@*Psh}Q@ z{--8#C{&3Js|Xv=(lY6hWAo;_C*RG9eRJaD;+{EkV9qp+vE$JjTlKeVTWgyGKZeZa z`1Ib;^ylaMx!I;M+dk?yTcD*!&f&-yY-Y#zjQoL-ZyNc-+_lYUGis%g)NZ#!b?&RX z_u=cWD!n{d-&#&#~z3)7^)8wP9wB*LdYRxHj;4& S{Ts<>rTPep`4_}6HvIvm+|}&> literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/should_api_be_triggered.cpython-312.pyc b/SMS-Exchange-Linux-GUI/api_interaction/__pycache__/should_api_be_triggered.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..076d0310aa952228b6e81ac07d6f60be2515e257 GIT binary patch literal 726 zcmZ`%&ubGw6n?Xt)J@a;s3sJ3u>pGtG~M0=Q9)`G1kEKVBnOw6-6UI+oiIB~vNZ(} z4_>8*;K_>zr6B$T9z1(VP!P902=?MZ2<9R=`6lU7FFu&>eecaT^WOaU6pJka+UxzU z^@{-f5J6zl37K3#G5`Y%(t^s|lL|4UXHbzml9hi7VX+qIMHIpzgf^yD&h@jS)dMBZwd8JqGR;|h{YR^+kHJ35d=CjBV zmzY7D-q)J6ZEBv&8`>>ebK59!w9?&DZo5}&R_%tFyJOjIFITvCTdQ^~9c!DcS`!;< zPLsMVLl^0Xrp}qwXqe12Haeca@}D`Dz{;Y!Q$lzGV<{3&AFG#M6w@LqWPkDo7nPpZS!%~5jm{ew|rYp87fIf|;kK?d5v*?s%w&G+Wb z``*ZY+T9%kTt5ElvGG&};14lrODHf76WrJU7+{zOORXzq|( zbKp8)oTaufQDY$4&@iB32ynP6F9K68fmLY{lwbu`3T)zvdQPz8cSoZIMm{-D; zDDHaJy~P>ZK4y(q=8w)@gf|VYgImCnOQBZ95G?ZSt(DY;8L!8t)@m6UHqtSs#Bsa} zEsw1`PRXLUJufzi8RAiRsBAl_%q3!A>dO8#oXFAdyq$6x( zm|>YZEqnbfo=%8BhKWA<{1dM)ATS{KjJwTG+kGiO3l4(~-ZDASS&J5Q#zc0W(@%+* zg-X<5L>O5sk2&A*OwnOh0r};q;{3>GP+aF^ATPc-#rj;C@v&)_+x6@1CeG;G0I`cFUPFJGVb|F<+ zyf!rqc7}VW-jjC5A=kUH*QPaTSCgmjM0ekYT&E=3$D#C!P@;XmfJ3eU6&t)zCJGiV o=E*&JlTXEei*uJNUJQf{psxF)0pjcaXv$ZhsPW~R-r$k{0L>EQ0RChPcL)x%bDc7qKm{t7152%$TjJ>2lk?>HC7x@^guJ*U zaliwRlxX;YT?agU zb`H`bZGsBOzNmFTD!1iGH@H0zo;Jd>2ZC=Sco`73XLIa<7F@JDZwM8xB2@T_N0n6X zEpbC6vTNg2LEn%_$i=C?iqr`z>2l@Su*-GkZ-6RSBuf3?3L9SXnybn7x?E=_?c`U))>JTW zsKp$zhhCOyCcKI?eFf5EsvQZ;Pa0&7j%OZjH31fzg-TVNj8f?CWM60$vv5h-FFsZdpj0u>V~P}R~zGjs)) z?SWQ!JMn{>4ljH-ZTC5Gck=Qdu^U!byw5?i&^rd+)M6~bkQV69yZ;SnO~4a(`5Y{cgJonl`--tRW6d1)TB|;bB3at zDYKBwlvS)GKSEkAxl+_pmuD|0r`FOLMPEV5OPXF>OHxl$H0B5^X#z_c$v|3^H0jGw zDHK>yq-l*pdI_?Vt(C_LWt+MBvJ@xjaf0+QWAw7S1{$%G_1M{J>}fq}8c zz@bKOg8lnO{|ZP)B}*848V0eW_2Jp-@N8|ES{~dMWXu1Sm7KUQOm6qZ>V4zYzHzJf zox6&4e9k&H|MSOI54<+>R05*+vzbq3zVd8(Z+bVoZ+71f)WV1FlHY_=RO#>feD&+M zYx2kw;1Ne}pV;;Vzm&g_t)5ejo}t_4{^2=!^chc8P5twy2@o2%C0l_v{sx@5zY&f9 zN)OFbcK6vK7qx4$%jn0!i4?dOicCuUz0|%*p8v_iF)E3Z-QGk1M=1vHr^N0`8yJnX zKUl5a7~eBvW3Om0%q~;>IwJ{21{qFu+p20`yl6}C;NlK_Q z9QOdo4?y4{IQS4OJc>+Pkz_qGU5!lFA~P1~{{x7YG-@Tz-Usjf4#aE5jdFe9Sasmo PeQ8UoRr+1oJ3VN1_pKpegf)0Laa<| zk-BxlchCt5OSa$hdzS3CG(8d=X1y@y+&=@^h5QAZ34>Rm#gn)fS}w#i$#s Lq)Z3#x5WK#qH|`9 literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/interact_with_rest_of_app/__pycache__/which_profile_is_being_used.cpython-312.pyc b/SMS-Exchange-Linux-GUI/interact_with_rest_of_app/__pycache__/which_profile_is_being_used.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..96b75102514cea36543cf2fe236d6a43f8f1d71a GIT binary patch literal 1447 zcma)5L2DCH5T2LKCYyBAHcgRgp{_)+wWP6#5{n9I#fn;#qS$%}Yu{_KHBI8%O|wCS zih>r@wjy{Cq&;a-(7&KpFF|wAn2UJw7EKQ|C*NCln+Q@J*x7xVZ@zgm-{f5&;0I=H zKMUGJ7rYvC zzF<|kA&zx#inQ4$MC`c@6H)mBYeMqVAIzefM4k_pC-%kxIGdbN* zt`J2{D_Yth2|@?zJvMAKv%$cSjBHlJ1P@F$cg7_W*i##|Br@y~0T}jJVRNC7CDf1) z46j3rU7P1(^rviw&&m9+Jo|=Y%@v!5Z}4s`o0grg#v7xCOa%yoVJ$C@GbzKUnNw&W z|DSUl3a}xlI7<0tC|`8S2TeW9^?A!eilobeUeL>Kl_qA(VwN)T$^v)(i)t!IECtJM zVrs@J)L0hOXQRo?42c$UMj|?#$){5p73)zw8%Y*0RU@-ROGOenEjo5~EONq}OseSw ziJZ~WIWuzd!l@|V4ysNX@w{dvJ${8~=|nuIvt7v+ z%H5m9X$QMm8+&w}U+$#QKiy6yAmr^L;+b7mG^VahYigcYG(Zf_49=y<5!%U)d=Bffh=rj1g2%b6pj(O9( zb$D^`z0k=z7dt;mfnsZTdF^RVE0H3;$+HU*nFZ+f>M3kYvz#QZPJY$b>Q literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/interact_with_rest_of_app/process_the_proxy.py b/SMS-Exchange-Linux-GUI/interact_with_rest_of_app/process_the_proxy.py new file mode 100755 index 0000000..f8b43ec --- /dev/null +++ b/SMS-Exchange-Linux-GUI/interact_with_rest_of_app/process_the_proxy.py @@ -0,0 +1,42 @@ +import os +import json +from core.Constants import Constants +import interact_with_rest_of_app.which_profile_is_being_used as which_profile_module + +current_profile_number = which_profile_module.which_profile_is_being_used() + +print('the current profile number is: ', current_profile_number) +print('the path is: ', Constants.HV_PROFILE_CONFIG_HOME) + + +def process_the_proxy(returned_data_as_a_dictionary): + proxy_ip_address_in_GUI = returned_data_as_a_dictionary.get( + 'proxy_ip_address') + proxy_password_in_GUI = returned_data_as_a_dictionary.get('proxy_password') + proxy_username_in_GUI = returned_data_as_a_dictionary.get('proxy_username') + try: + proxy_port_in_GUI = int( + returned_data_as_a_dictionary.get('proxy_port')) + except (ValueError, TypeError): + proxy_port_in_GUI = 1080 + + # Create a new dictionary: + new_formatted_dictonary_to_write_to_folder = { + "ip_address": proxy_ip_address_in_GUI, + "port_number": proxy_port_in_GUI, + "username": proxy_username_in_GUI, + "password": proxy_password_in_GUI, + "time_zone": "America/New_York" + } + + current_profile_number = which_profile_module.which_profile_is_being_used() + print('the current profile number is: ', current_profile_number) + custom_path = f'{Constants.HV_PROFILE_CONFIG_HOME}/{current_profile_number}/proxyTEST.json' + + # Ensure the directory exists + os.makedirs(os.path.dirname(custom_path), exist_ok=True) + + # Write the dictionary to a JSON file at the custom path + with open(custom_path, 'w') as json_file: + json.dump(new_formatted_dictonary_to_write_to_folder, + json_file, indent=4) diff --git a/SMS-Exchange-Linux-GUI/interact_with_rest_of_app/which_profile_is_being_used.py b/SMS-Exchange-Linux-GUI/interact_with_rest_of_app/which_profile_is_being_used.py new file mode 100755 index 0000000..e2bedee --- /dev/null +++ b/SMS-Exchange-Linux-GUI/interact_with_rest_of_app/which_profile_is_being_used.py @@ -0,0 +1,25 @@ +import sys + +if len(sys.argv) > 1: + try: + print('the profile id is: ', sys.argv[1]) + assigned_profile_id = int(sys.argv[1]) + except ValueError: + print('Error: Profile ID must be an integer.') + sys.exit(1) +else: + print('Error: No profile ID provided.') + sys.exit(1) + + +def which_profile_is_being_used(): + if len(sys.argv) > 1: + try: + print('the profile id is: ', sys.argv[1]) + return int(sys.argv[1]) + except ValueError: + print('Error: Profile ID must be an integer.') + sys.exit(1) + else: + print('Error: No profile ID provided.') + sys.exit(1) diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/generate_random_number_string.cpython-311.pyc b/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/generate_random_number_string.cpython-311.pyc new file mode 100755 index 0000000000000000000000000000000000000000..f6968ba5c535bc4b39883c2bba068c60647c101e GIT binary patch literal 1324 zcmb7EO=uHA6rR~^(%Rb4TASF4ZA32t+im)1g|=u_Bs3IJ6fDTHW+p#nvm0kO(3Avn zsHjB{#nOWcIY>?ErAGw|J&GVCkVDy%;Kg2~&`asbH=8u16$`$d{qknsn>X{`_ck9} zTAC1u`TJe$J4WaypB#u#Rdzj~EF*#lR?!S1B5^F>8BFk9OZ z-ra8iPaUuw=Rx~hh_HZ6?pc)#T7fugwOBXM3Ru<-%tx$?4&unyZ1u`BM+6gbp|L(T zab^&4t-xt(wG)qzpT(phgWsa}LRQEKkZ|L)bvRKG4jqJdcLHDvVW?CFJv@`eW-SGT zW@|b*lE8hmj4^uAX;)LQn)(9+gG0k3mq)Km`vuFz6piQ!%N364@i2uIp|9V+aB=4AksC0t{sEsLKE8Jxic&4cBM&3w9Y2z+N@ko=~wTv>wPe6ma2u;o9njg7bqLmW~YO=4W#LSu23m zFnRC6%{zlK^oBUA$2H3d%tWbQv|K9HqGrr$1+Ei{X;M<9$!d?pHQ?5ustO%Z;f}RK zG=t~t^ZBmYnOWzKC6IN2Gp~g47+^1lw%n~Rql?iBIUB>9p3mc7#$i_K2$lie!LmD; zyY<7{wLJHFu0E{|=O<;;^R=xsI#nK>0!yhUR0i~h%HB{>JiXO5QoJ}+1cV`ax0<_) zVz*rgKW6*}eu42n9Q#JBjcaz5I6eD~V+oz4R64=V!jylAc8l#eFveS`C1*c7q7(P* JpnrfJ?GMbSPOAU_ literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/generate_random_number_string.cpython-312.pyc b/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/generate_random_number_string.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..627305855b71a29e843a7e4d8106c555863d970e GIT binary patch literal 1133 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 literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/local_logs.cpython-311.pyc b/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/local_logs.cpython-311.pyc new file mode 100755 index 0000000000000000000000000000000000000000..d87ff50c2fc2d3ecd4a12e9a324ef71eef86a7d1 GIT binary patch literal 10803 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 W{-8iE*5Snpq|ZgOSqccbNB;xn`BhW^ literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/local_logs.cpython-312.pyc b/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/local_logs.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..3f064b7c2c97a99406fbe2931dbb4246756add32 GIT binary patch literal 8886 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 PuT;^VY?qy8$;|%?=+u79 literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/search_or_setup_json.cpython-311.pyc b/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/search_or_setup_json.cpython-311.pyc new file mode 100755 index 0000000000000000000000000000000000000000..e4029fc0d3a20e84bd0e7febfa8a948260abb6a1 GIT binary patch literal 4260 zcmbtX-EZ8+5nmp8cRW!#ecQ6+IJ7PKbkWDfb`x2Kr8>5gHZ`g^ae=}gC_x`79VLo9 zEP0ltQo^AKP$Li!!!RHLg#q=&Rp312B|sha7OH5_i(n{nNhlhN>YKHaKkWKnZWtJ(oHp+XK zJLua%&w%53h07YWD{X{kE4wuEG009-7g87p{Q)VFr)>Rd3^F?R;bZsm9UybGx<|F; zAcuJdr+HpE(K36${0c{PHbPE=l-958mg=|zH($T{duW-nTdN$ie7WsJ9MI6$v1f2k z&ntJu5Pib0eigV2;WRpnEN&t4fW3tl7zW)!4E*YDDDE(DllqIs+tcEHV=nh|hjUIjX9nLw4o zd_ElwglT##iOx@wA&Ceo8S=aubSdhzT+nTa_Ln3LYPjgEL}ivm>`Wx(&BIL2oL4gi zOU0QRi+0X5GWm1)kvufi5u-4FPsNs$)m7P0mCTjGqKc)fx&{{^O`BMvY*NUUq1Q{h z3whm?m5gp?WnEHaTbAHNShh9Ourih^<7`fX*_LV-@>J&0{9+(xb82=@k_|-))douu zP0}7BI_?3fiOMV)e71;Q3N5Q+Urv58xjy6xXMEwzE{aCSU-C_>!lUaRFZ#Ub^5PEP z;wIl+?*kH6k3Z}4XI)xflEE=DI2Klqzu@y1T>iq3F?6Ko$*;ek#{yf{!VtA zFMG|G{pQQi*k#Fh$Q9Cm(HZ}yw6_1C_UqTL4;rFplGmr)q#Ra{zvuJ!+;XMkH^}%6 zsDFmDlQ&e4|J3I{b<5T2fUDkmr{`*teUap@cEn$FGeGN*I0h^fi90|eYl!+LLp=H^ z`+s6ozfDlSRFsIr0!r+Mqcx~ZaMFo1Vv{YDS0PBaFV@wd;cR7BhpR`J<>=v1&WQpZ zMW@~{8BFkV>HUR3mhK zIq}8BdZ&Bhf+vjo!nn(gzk(r@t<4T9M|lh*hs&W9rol5J2V^6a41w%kE|5bsWD3hH z_3lUsH#mob>texkR+f?(Yu*}BA7pc~F{5VET-6hTCiOucf(40OI0>smkZfPbX%JdU zal>BBt3lE#+$(+4P|5xLlV5%q2oNKuwV5!Qwvp&a<5t*fRl{TG4<|rt5;$q-M&>ka zmllO6h%;n&c&wiRDI)3!e;3~RtMJx())P+o!l~l5osO<2skPz9!|S#?@V?hE=68%0 zuW$DbxJN&P`ps{`x65^H3w_{Cn5Z;cn-5m7whQ!lIE^)CvsTytob`ef3QHR}8u)8{^f;=@=o5|K-cdWreIg9d}|1`!&}Xw+<(<6Q|Jz_kkpsXa^J1!Ng|LiK^3t;RF7qA?h;K z@PUt$zIMXSH-?aQf;J&C*(L-KLkZd{pIFW7a#qFNWIl;0_yiD(91l>7mXZ^dIB7a( z$@kULl4Te>4>R5+Q?-MVyGZn8V{&(Jmc}=IzVQ2%->p0{y!e10A0Sy;dQXxz2sv8k z(I?~Ux4h1j-w?I2!fPG$TL&R> z#n9WC;x#wX>v4TF*gZ4=B@(Cn#3>S}MmDq^zIiqAsDC}NdD7*FJ$~5dhoM1Y-Uwx( zgv7iN67y>Ms-x9bDdz3rf<(3rqFz5-`4-!KrJvpE=dKLKw}u#?FOKzGonT)~aMzgl zUpNM6Iv!dP$u+{%gQNsB_)z@AM1Nl)3R_g+Z}>~|rc%(=N&FrRk$>5i2?UP8Fxx0m wq`z$>6zOl5>tsHIl(>ctCz!TfR3SYKa}kbJCNYjVzKbd(d5kdcB~+mQ08bpB`v3p{ literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/search_or_setup_json.cpython-312.pyc b/SMS-Exchange-Linux-GUI/local_data_operations/__pycache__/search_or_setup_json.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..50d88cd5498947bc62c739fbf0822c97f720584a GIT binary patch literal 3620 zcmbtWU2NOd6(&VeqD)J+!;dje!ETw+9Ot0{CGMF4BiS?y+rN2K0r6Y&2kvqQLUfw;(By!B0DfKa%XE zGuB-}mzU?>b9nB(=ljn2IudE2p#A-?B{kGaQUAghzXiO(qvv6;Ny(H<=cpO?Nzc%7 z;Lp@dKxUw4WEOf>=Ah@~AoRg9oe2Gi2BtEMX9pi4_~ZMd?`gDYqReUY{?~i~Jm(2rmWScH>#0 zD)b$1M@!5R`cKRcJUBzIoT>=2LU$!_L{Y+~yi*SEl-@^OQlC0yK4lqT%<+@B(v#D$xmHYLS0c z&&diAbo| zHK%~~g}Sy_Qq8QG(KQnmT@wEk&nt!@%_;FqVmzzla=KX3NluP0B^SF7e@0X_uoZ|W z6Ja}`8#Y^z%&Z-BeX#kwbW@R4V%S`PsG4cB^SY|ptX@!{pEq>qoElZ}91{aBBs=8*R3`HWDY+5I2Lotg5 z$BAU2Y>Sz!lDV0dG&$|wL)zN|O3)W_0^GnmFusOvg}N_9)-JAITpM2y>#0K5*8N}ZCBEGmHpOwBr>JOTJR z70gF{+l^<1^^n|=bQAA-z-DmS%Hrw9+W7GI2uvaT4SrkgH0#j;{1MR8ge z&8#98h(1T8yr|-ek_eblwK-8WZJH!_f_oyEQ3&pVpu0|75o9WYBxSQXU6K<)attM% z*ma@!_-rwka{!e_ggbabIFTMl3B%mLyK;aclH(}tKvOQvBqJ@W8Izm=c`y8pCFoYD zd(RASMYiAGUbd3sR^P8JHn!IYYpeJCj_^FjvS6LMV8uqQ(RnL+bBE9E@q^p3&o%4S znH~Q35VI{&D>|@c)WSm$Q{36@@?Kl#T6wixJy~n(zr{j;a%X=K+E%VV=KPTxc3-yj zTuCusrnoC(2g445=7ilj7+~1V*K-*Nyyk?3mqn(j1U;3YZDvj}6O8TB2X5JBZYpKF z*C(A1q+C%+tFvjiKY(~qlMVb19GiP)$2@`nrL?NK$RB_O=!bzf0f#1ZtzBNdT5REDf~M8jS1*hC@(_4 z6;6L6oUUeS!m}%rd&jyq;~VkK;f>*{2^?EHc5&tUz21T9=`HQ^KUkxa*72(r+jUQf zL5LH)%S>}sfxvO1EdY1;OKz)COBvn&L)8VJb=y;`yE*~-t0=%hQ{BWJ5f{xn^h{Lh zl?fSYqEQZ_&5K^Bn}Uss>ZvputVd?(FpX;6N9fkSzZ9ylABHN-%i!4oPXa&V$*x1HTBOnBXxIjF3dQ0S}kIF>^ZLXz({V zg|ZG@&L8IR4kQ(qfJ_}2T$Ang`YTZiIVq!%Zq!FoCwgQ8@$Cn2vTQKE0b2Z_Zv3mB#K)aKsNj==82Ilb&qdd3$KRP z&sM|R&+PKUm?=g;skI$)Ma;Ll|G29m-Z!ui`-F=oUca-pu e?WEtK9}b7<_J=2E`qIN7OP_iaJxRAaX8r@hW%qLc literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/generate_random_number_string.py b/SMS-Exchange-Linux-GUI/local_data_operations/generate_random_number_string.py new file mode 100755 index 0000000..67ac5a3 --- /dev/null +++ b/SMS-Exchange-Linux-GUI/local_data_operations/generate_random_number_string.py @@ -0,0 +1,16 @@ +import random + +def generate_random_number_string(length=10): + numbers = ''.join(random.choice('0123456789') for _ in range(length)) + # Insert dashes every 4 digits + formatted_string = '_'.join(numbers[i:i+4] for i in range(0, length, 4)) + final_seller_string = f"BUYER3_{formatted_string}" + return final_seller_string + +# Generate and print the random number string +#i = 0 +#while i < 5: +# print(generate_random_number_string()) +# i = i +1 + + diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/load_or_setup_config.py b/SMS-Exchange-Linux-GUI/local_data_operations/load_or_setup_config.py new file mode 100755 index 0000000..4873865 --- /dev/null +++ b/SMS-Exchange-Linux-GUI/local_data_operations/load_or_setup_config.py @@ -0,0 +1,54 @@ +from local_data_operations.search_or_setup_json import get_the_path_of_the_folder_for, load_json_as_dict, replace_and_save_value_in_json +import json +import os + +def get_default_config(): + default_json_content = { + "error_log_file_path": "error_log_for_gui.txt", + "local_data": True, + "default_currency": False, + "turn_off_email_option": False, + "turn_off_proxy_option": False, + "cache_available": True, + } + return default_json_content + +def load_or_setup_local_api_data_folder(): + path_for_data = get_the_path_of_the_folder_for('.local/share', 'api_data') + + # Check if the folder exists + if not os.path.exists(path_for_data): + # Create the folder if it doesn't exist + os.makedirs(path_for_data) + print(f"Folder '{path_for_data}' created.") + else: + print(f"Folder '{path_for_data}' already exists.") + + return path_for_data + +def load_or_setup_config(json_file_name): + # setup configs file: + path_for_configs = get_the_path_of_the_folder_for('.config', 'sms') + + default_json_content = get_default_config() + + raw_data = load_json_as_dict(path_for_configs, json_file_name, default_json_content) + + # Return data in searchable format: + return raw_data + +# for the initial jsons from the API: +def setup_path_to_dump_initial_api_data(filename): + path_for_configs = get_the_path_of_the_folder_for('.config', 'api_data') + final_file_path = f"{path_for_configs}/{filename}" + return final_file_path + +def replace_config_value(json_file_name, key_value_to_find, value_to_replace): + # setup configs file: + path_for_configs = get_the_path_of_the_folder_for('.config', 'sms') + + default_json_content = get_default_config() + + new_data_set = replace_and_save_value_in_json(path_for_configs, json_file_name, default_json_content, key_value_to_find, value_to_replace) + + return new_data_set diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/local_logs.py b/SMS-Exchange-Linux-GUI/local_data_operations/local_logs.py new file mode 100755 index 0000000..6acdc34 --- /dev/null +++ b/SMS-Exchange-Linux-GUI/local_data_operations/local_logs.py @@ -0,0 +1,290 @@ +from interact_with_rest_of_app.which_profile_is_being_used import which_profile_is_being_used + +# Loading and using JSONs +from local_data_operations.search_or_setup_json import get_the_path_of_the_folder_for, load_json_as_dict, search_key_in_json + +# Generic: +import json +import os + +def return_profile_filename_and_path(product): + # filename: + current_profile_number = which_profile_is_being_used() + if product == "email": + json_file_name = f"email_{current_profile_number}.json" + else: # this is sms: + json_file_name = f"{current_profile_number}.json" + + # folder path: + path_for_configs = get_the_path_of_the_folder_for('.config', 'sms') + + # full path: + # Check if the folder exists + if not os.path.exists(path_for_configs): + # Create the folder if it doesn't exist + os.makedirs(path_for_configs) + print(f"Folder '{path_for_configs}' created.") + else: + print(f"Folder '{path_for_configs}' already existed.") + + # Full path for the JSON file + full_json_file_path = os.path.join(path_for_configs, json_file_name) + + return json_file_name, path_for_configs, full_json_file_path + +def check_if_profile_exists_already(full_json_file_path): + # Check if the JSON file exists + if os.path.exists(full_json_file_path): + return True + else: + return False + +# When a profile is initiated, we want to know if it has a country and proxy already assigned. +def get_profile_location_and_proxy_status_as_tuple(): + # get the path and other variables that are not needed, but have to be unpacked: + json_file_name, path_for_configs, full_json_file_path = return_profile_filename_and_path("sms") + + # Check if the JSON file exists: + if os.path.exists(full_json_file_path): + # if so get the data: + with open(full_json_file_path, 'r') as json_file: + data = json.load(json_file) + + # get the location, or return "none" if it can't be found. + # return json_dict.get(key, default_value_if_not_found) + assigned_location = data.get("profile", {}).get("location", False) + assigned_proxy = data.get("profile", {}).get("assigned_proxy", False) + if assigned_location == "": + return False + else: + return (assigned_location, assigned_proxy) + else: + return False + +# If it does not exist already, then create it from scratch: # darth vadar +def setup_email_config(email_operator, full_email, email_password, email_url): + print("SETUP EMAIL CONFIG triggered") + email_json_file_name, path_for_configs, email_full_json_file_path = return_profile_filename_and_path("email") + # Add the email data: + new_data = { + "email_operator": email_operator, + "full_email": full_email, + "email_url": email_url, + "email_password": email_password + } + + try: + # Update the JSON Profile with new data: + with open(email_full_json_file_path, 'w') as json_file: + json.dump(new_data, json_file, indent=4) + return True # it worked: + except: + return "error" + +def wipe_entire_profile_data(): + json_file_name, path_for_configs, full_json_file_path = return_profile_filename_and_path("sms") + # Check if the file exists + if os.path.isfile(full_json_file_path): + # Delete the file + os.remove(full_json_file_path) + print(f"{full_json_file_path} has been deleted.") + return True + else: + print(f"{full_json_file_path} does not exist.") + return False + + +def wipe_email_data(): + email_json_file_name, path_for_configs, email_full_json_file_path = return_profile_filename_and_path("email") + # Check if the file exists + if os.path.isfile(email_full_json_file_path): + # Delete the file + os.remove(email_full_json_file_path) + print(f"{email_full_json_file_path} has been deleted.") + return True + else: + print(f"{email_full_json_file_path} does not exist.") + return False + +def get_email_data(): + print("READ EMAIL CONFIG triggered") + email_json_file_name, path_for_configs, email_full_json_file_path = return_profile_filename_and_path("email") + # Check if the JSON file exists + if os.path.exists(email_full_json_file_path): + try: + with open(email_full_json_file_path, 'r') as json_file: + email_data = json.load(json_file) + email_operator = email_data['email_operator'] + full_email = email_data['full_email'] + email_url = email_data['email_url'] + email_password = email_data['email_password'] + packed_email_data = (email_operator, full_email, email_url, email_password) + return packed_email_data + except: + return "error" + else: + return False + +def wipe_location_and_proxy(): + # then get the profile number & path: + json_file_name, path_for_configs, full_json_file_path = return_profile_filename_and_path("sms") + + if os.path.exists(full_json_file_path): + # if so get the data: + with open(full_json_file_path, 'r') as json_file: + data = json.load(json_file) + + # clear it: + data['profile']['location'] = "" + data['profile']['assigned_proxy'] = False + try: + # Update the JSON Profile with new data: + with open(full_json_file_path, 'w') as json_file: + json.dump(data, json_file, indent=4) + return True # it worked: + except: + return "error" + + # if it does NOT exist: + else: + return True + + +# If it does not exist already, then create it from scratch: +def create_or_add_to_profile_config(config_file_data, peer_to_peer_billing_id, chosen_location, proxy_or_not, chosen_service, email_operator): + # first check if the user disabled local data saving in the config file: + do_we_want_logs = search_key_in_json(config_file_data, "local_data", True) + if do_we_want_logs == False: + return False + else: + # then get the profile number & path: + json_file_name, path_for_configs, full_json_file_path = return_profile_filename_and_path("sms") + + if os.path.exists(full_json_file_path): + # if so get the data: + with open(full_json_file_path, 'r') as json_file: + data = json.load(json_file) + + # If it's a blank location, then update it with the new choices: + pre_existing_location = data['profile']['location'] + if pre_existing_location == "": + data['profile']['location'] = chosen_location + data['profile']['assigned_proxy'] = proxy_or_not + else: + pass + + # Add the new order: + data["orders"][peer_to_peer_billing_id] = { + "chosen_service": chosen_service, + "wants_sms": True, + "completed": False + } + + try: + # Update the JSON Profile with new data: + with open(full_json_file_path, 'w') as json_file: + json.dump(data, json_file, indent=4) + return True # it worked: + #updated_json = json.dumps(data, indent=4) + except: + return "error" + + # if it does NOT exist: + else: + # We are creating a new Profile Config: + + # stock the JSON with values for a new profile: + default_json_content = { + "profile": { + "location": chosen_location, + "assigned_proxy": proxy_or_not, + "got_proxy": False, + "email_operator": email_operator + }, + "orders": { + peer_to_peer_billing_id: { + "chosen_service": chosen_service, + "wants_sms": True, + "completed": False + } + } + } + + try: + # Create the JSON file: + with open(full_json_file_path, 'w') as json_file: + json.dump(default_json_content, json_file, indent=4) + return True # it worked: + except: + return "error" + + + +def return_all_locally_saved_orders_for_the_current_profile(): + # get the path and other variables that are not needed, but have to be unpacked: + json_file_name, path_for_configs, full_json_file_path = return_profile_filename_and_path("sms") + + # Check if the JSON file exists: + if os.path.exists(full_json_file_path): + # setup a list to save the orders: + list_of_all_past_orders = [] + + try: + # if so get the data: + with open(full_json_file_path, 'r') as json_file: + data = json.load(json_file) + + # Iterate through the orders & get their past details: + for order in data["orders"]: + chosen_service = data["orders"][order]["chosen_service"] + completed = data["orders"][order]["completed"] + order_data_as_tuple = (order, chosen_service, completed) + list_of_all_past_orders.append(order_data_as_tuple) + except: + return False + finally: + return list_of_all_past_orders + else: + return False + + + +def delete_an_order(which_order): + # get the profile number & path: + json_file_name, path_for_configs, full_json_file_path = return_profile_filename_and_path("sms") + + if os.path.exists(full_json_file_path): + # if so get the data: + with open(full_json_file_path, 'r') as json_file: + data = json.load(json_file) + + try: + # delete it: + del data["orders"][which_order] + + # Update the JSON Profile with new data: + with open(full_json_file_path, 'w') as json_file: + json.dump(data, json_file, indent=4) + return True # it worked + except: + return "error" + +''' + # see if email operator is blank even though they have one from the past: + if email_operator == None: + # then get the profile number & path: + json_file_name, path_for_configs, full_json_file_path = return_profile_filename_and_path("sms") + try: + with open(full_json_file_path, 'r') as json_file: + data = json_file.load(json_file) + email_operator = data[profile][email_operator] + except: + email_operator = None +''' + +#email_operator = None +#full_email = "test@t.com" +#email_password = "dd" +#email_url = "aa.com" +#config_file_data = "a" +#setup_email_config(config_file_data, email_operator, full_email, email_password, email_url) \ No newline at end of file diff --git a/SMS-Exchange-Linux-GUI/local_data_operations/search_or_setup_json.py b/SMS-Exchange-Linux-GUI/local_data_operations/search_or_setup_json.py new file mode 100755 index 0000000..46dc0fb --- /dev/null +++ b/SMS-Exchange-Linux-GUI/local_data_operations/search_or_setup_json.py @@ -0,0 +1,74 @@ +import os +import json + +def check_and_create_folder_and_json(folder_path, json_file_name, default_json_content): + # Check if the folder exists + if not os.path.exists(folder_path): + # Create the folder if it doesn't exist + os.makedirs(folder_path) + print(f"Folder '{folder_path}' created.") + else: + print(f"Folder '{folder_path}' already exists.") + + # Full path for the JSON file + json_file_path = os.path.join(folder_path, json_file_name) + + # Check if the JSON file exists + if not os.path.exists(json_file_path): + # If it doesn't exist, then create the JSON file with "hello world" + with open(json_file_path, 'w') as json_file: + json.dump(default_json_content, json_file, indent=4) + print(f"JSON file '{json_file_name}' created with content: {{'message': 'hello world'}}.") + else: + print(f"JSON file '{json_file_name}' already exists in '{folder_path}'.") + +## Load JSON file and return it as a dictionary. +def load_json_as_dict(folder_path, json_file_name, default_json_content): + full_path_with_filename = f"{folder_path}/{json_file_name}" + if not os.path.exists(full_path_with_filename): + print(f"JSON file '{full_path_with_filename}' does not exist yet. So the program is now making it") + check_and_create_folder_and_json(folder_path, json_file_name, default_json_content) + + # Regardless of it was just made or not, load it, + with open(full_path_with_filename, 'r') as json_file: + data = json.load(json_file) + return data + +## Search for a key in the dictionary and return its value or a message if not found. +def search_key_in_json(json_dict, key, default_value_if_not_found): + return json_dict.get(key, default_value_if_not_found) + +def get_the_path_of_the_folder_for(which_folder_type, subfolder_name): + HOME = os.path.expanduser('~') # Get the user's home directory + config_path = os.path.join(HOME, which_folder_type) # Create a path to the .config directory + path_for_configs = f"{config_path}/sms-exchange/{subfolder_name}" + return path_for_configs + + +def replace_and_save_value_in_json(folder_path, json_file_name, default_json_content, key_value_to_find, value_to_replace): + # Check if the folder exists + if not os.path.exists(folder_path): + # Create the folder if it doesn't exist + os.makedirs(folder_path) + + # Full path for the JSON file + json_file_path = os.path.join(folder_path, json_file_name) + + # Check if the JSON file exists, + if os.path.exists(json_file_path): + # and if so then load it: + with open(json_file_path, 'r') as json_file: + data = json.load(json_file) + else: + # otherwise use the default values: + data = json.load(json_file_path) + + # Replace the value of the key "key_value_to_find" with "value_to_replace" + data[key_value_to_find] = value_to_replace + + # Now write the entire thing into the JSON file: + with open(json_file_path, 'w') as json_file: + json.dump(data, json_file, indent=4) + + return data + diff --git a/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/convert_to_dictonary.cpython-311.pyc b/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/convert_to_dictonary.cpython-311.pyc new file mode 100755 index 0000000000000000000000000000000000000000..8a6e20bc01e98fc62c7946a19398126a88d80c14 GIT binary patch literal 947 zcmZuv&ui2`6rM@4OWREat*uyS=?c}Z(ndX$9?F8+L%kHmTeXCknRcVuOq@vyk!)GC z2M;}15sIL&inK~WJo;yBrQniN!IQUzy+}{KN!`U|eaZWH^WMjM-~8Ac92`Jk#V7sF z7mUzPxoDg6H)x%OUE^JF2s#h_PHbD*x(tIcm&a0263ul)kZ6x-Bw(e? zTum?$vNkbs{M;z9GBrX$xp5~7O3X9->;AM40iE{3@H1mXJaB7h#O^3eAEMoYa*;EMA@*R^{fo0gtTciX30W)_X##;~hz;{XR^i-&Lk+Grz} zuWNapgZ}c)9|`8AQ$M3Lmr6VCn=dmGy0pkgfG6LaxCGEtF~$v)tEOL58^9Nus29>k Fe*lv7?WO<# literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/convert_to_dictonary.cpython-312.pyc b/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/convert_to_dictonary.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..1be5214ffaed8eb33740b63c9f3ab6d8c5541e2c GIT binary patch literal 696 zcmZ8fL2DC16n?Wio0cZ2*wRW14UJOi9^&Gqh=@>#n1Ti*dMT7;ogFtDlijehn|5I% zJ$UdC(9%N=dZ;L<6hu7x54=Q04eO=g$y;bn_T)^-9?S>tW8Uod-uGr_K4-I2!0~#2 z+kTG#ev2f5G+GR2_@WCYn5Yh$U`mf+6NN~X{|G^uBs!5z@Q`^7KXK}U1#KxpMcBFs z(3T^J&h3`_XXlPVR@5iTQF``S(2e$@ z{YPKZEB(yk&rJSHCV#N7v{m`H)}7~UR`?Tr!%~RA>RjYn$yYTwT5d3b$Z>K<*B%D UmgO{%5kkKpJ;YP!yeD4cKXe(Z9smFU literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/extract_a_list_of_values.cpython-311.pyc b/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/extract_a_list_of_values.cpython-311.pyc new file mode 100755 index 0000000000000000000000000000000000000000..f1113e9cb44225a44c5bbf3ac428c4e6b8db97fa GIT binary patch literal 1478 zcmcIk-)qxQ6uxPa&KgT&otwXKZa!!Qm$8935kVb-ibEKJ4kX0fYa5#;;ojTXLI!;h zCNgjgVM7q>%iQpvX{8V4f-n#td@BxN?8$rM+F3^*eDE~=I4AdZ*6^NMYOk_I?M$RuFqeu`o?w4uK_l#gXxEOE;UG$2D zCkPYMc9G>FXxu245jJnS4)UmYk{P9$ztaqiELe_i7XvYd5n$g&gqT*~n4${$QlF@@|Em$O{e?@GU*?=ECZudiq==eXer%XB-^T7q2Yk z>)J>|8>vifCR3GLO})Pb6m=|um&zCI=n{N4Ro8|a+HecViLuSpk=LbHrPX*nHPlEA z)y__QPEFKO6HR?!CApkjh3|83bJe-}>CwjN(YkIlbfcyl+fD6o<=z(W19VAVNGp>3 z5AOU&$>075$&dFGYA?wj?^zLpa#rfzQg%!NGhp!!(h*U) zz~NssA*+-8`>T`tG!aWoHhXDe@Z?Hqxm4BGbL+G9!OM-o%Qb!X+HUo=De(aBB_scy zSBN(1asx#7qq%ktTrK#p=%Q=*6kivIAGyS#B}Hq)$ literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/extract_a_list_of_values.cpython-312.pyc b/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/extract_a_list_of_values.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..d524ab67eed68ba8ea34421e886b84c586395092 GIT binary patch literal 1289 zcmcIk&1(}u6rat`ZkujHLi&k{t$NTD+6cYWQar_P+e;9%Aj`5lO*Yx=hM7s5z!q}w zV4=_!52+wn!9z>`6fa^Zlu@Lh7jM;ike-~`X4{AsJm`ac^X9$Z`&i~T^ClMS0$g4{ zTd-fr0DKagP$DhkV2~RPU;#^Vz$~yLPr$5X$y`TjQVM<%uo*K%i=E0pUJV@l;Hm+r z#Fsz{?WmT|2ivXqVx$cTTj93Fj~pZA99V?DoB@w-1F)#jju7T6v@^7~TiuAX-0Ld^ zE%cwPmK0X>rQ#I;I5OqKLhJ+)TBqb6PZZXX!17%Pe3%6(d4@q+D$c8 zJj}EpNGP`598Wi>!BmV$#i0z^6qSfLiQzyFAExtO38iZlnoDOqvrGZj^0Zlue^5#fC|BBN#>Z=Ja{PsUR{|uCc+>g1C>j z7epWqS9S0?+20sh8(DwUOkS?v`>ulS#LDE-bJ25_wqd(;*`{B9&zHe>IwF7E)az0Z4==$ z9MvN-O|Jg_oMq)&`#JCae$E4D8`ZVyhPIjCoNW$Fyh}`c?ciCspZ7`0NB<&77EG`O q0)H^`VdqrIvnmd{j?eM9cwtDAt9@CLr1wDk24hn4U|5rmYW)N~a2E^! literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/read_from_text_file_into_list.cpython-311.pyc b/SMS-Exchange-Linux-GUI/process_api_data/__pycache__/read_from_text_file_into_list.cpython-311.pyc new file mode 100755 index 0000000000000000000000000000000000000000..dafe2e2ef78a0dba3f51425f4727957b90c27c60 GIT binary patch literal 1101 zcmaJ=&ui0g6o20&-PU%SKRO!_CW9R$&NWUZ9@Y(}-ejHNX)+11`ECoONys;K>qudT z9d_8k%|Si(G?gKE@E~4vH;=0ngq#Hbfk+ibPrjtCu8#WJ?}zt&@AG-z_a5Zsz(4}f z7T-M87dU|L;pN20AE(ieP6agBgh!x}hahqJlUzvY!NcQed_t(eGL(sXD(|6YA8Q}r zY1u6(a~@Yc#W~3U?4x_ozLt57+XRoVwzcgPIvT%^H4fT!?)|GK8g{Kg=j#N_H$5NSiq>A^m);U4-ECD0fQ%C1J z-1aqmn>5K)iTE+*I=U@!K9{-S3%W}SES!I2q`57xSOqE<8Fl0bC3nR#W&5T*ZlgoT z&0^sRb(oSjsA^J8zEdnwN4ab0)O3|4%TXel(xS-@RkczSF4~5rYO?KEdCHig+Pb2t zt{O3vCC4f#E?vV4xao~S)T~&b!TS{E3X=CCi7Qv4o6}c zgbg@K=UV@_lh54B`tJIUx95Eor7xoNYP2S1>SCr%X`lj{!jZ}-j+azX)nhp+)b52P+_ z-2c@BiNP)XMXDAbuE&Q1h{fhfb?Dp0bVb^gcEt5{X884NemC(JGpK*@C4N4LakbF&2JX>T$S5C$tqeGudI$*#fcmQ=G3;MXj1rZDpqyG(42l5aQ_NU(fgLH8&$2ACqhEU|% z33Nw15F27qnrI?5gzjkKCLB;*$b&BIoCgSKgBJPz35@6ct7nMgSuNpllA_yy8u)Dn zjC~SlkSuN>7y+$960U+zs>pLd@ZsH>n1d>jX(lAzfLs}nOEL|q%qYI;Gl^JeOvWmjsc+xPD%uIK2c@2i??sfNZhg*#DqJ*TWPv&Ph+ z1c+o}K!#81Kj} zxqZ1ALDl+A@^<6R#=F?@^{r3w%&WC0th3kJYd1b83ku7#7CIn_eLd1gBd;o z-l(~1!M(Z2tyHO;Je#lvA#A1%!5|fTmu7u){%hHrQ32DGVd5|Sw6;Q=VFc6BzL_aTAb*0uN zJ*-7ljpVxXFWx{z+{+Y~-m6hM5V4m$O*Rv_@Xa`j_PJCf2sw>8^Im2nF3D~<+lpZ#uJ*u6`;ms`CVSfjlT*3Et)*#;_a1I(@GkziTKcccxp`dqaR RFl}Irr%em@r)U}U`+p+~yBh!i literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/process_email_data/__pycache__/filter_email_names.cpython-312.pyc b/SMS-Exchange-Linux-GUI/process_email_data/__pycache__/filter_email_names.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..d731f73ed2cda175312ca0f09c6b1c9376eca4ce GIT binary patch literal 578 zcmZXSK}*~~6vt<>s|o5hP-%r6BzSVgZ3JEEp|l4T5n3(WCd?$PyIAO< z-@t=@01qu*y!siu#P#5klh7|v*qbNcBno2xFmK-by*K|ENUm$O2?RPn>H1d~p}(ql z7Sx4CYUC7A^b75w9-8~TBdF~x`T2npQNAg`!g zjzLy^qL6o#-z(8^s$Xa&bWz>d?!OZxqCB)&Nc_O&F%u-=A|Eet--vkG>c1%`s4vNW zz-X>TJjZs9TXiiT3wW1_To)`3h{u4uPh+t1h-59V%_WOk#qoT)m@K#;-4aUmAlrV} zaoRj&PA^RkoOSM{A&U~}xZm8y#*x=1(E)3G^`rEtvAMhD#DaTF%F>}lNkW|OevmNn zL?RM0`62G*Z~w<)3NBQa%5?}o(a>7DvsQ1c)m!UhR-L)mt!%bA(3?YZW~f_doq;}| zEq=+?+`*zdG^g*)xjS>=#$5Qld|A0QS2AN|1U_iHjtl2MNYtPdlMo(^Pa&siz&;BT UO7&5t`VszBFvg>*ft$tbBe|lPH2?qr literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/process_email_data/__pycache__/load_email_operators.cpython-311.pyc b/SMS-Exchange-Linux-GUI/process_email_data/__pycache__/load_email_operators.cpython-311.pyc new file mode 100755 index 0000000000000000000000000000000000000000..356080f200a84806cfdb37a16b144c6c4020195b GIT binary patch literal 1338 zcmb7EO-LI-6n?Y2(L_zuL~5Z*Llt5U8d|kfDTSme)Poj0>1EmOju_eOZf7_CkrXK{ zEacQvZz;AAJoQatjJ7$nZ)U%I^M1a0v%A?het#RF zeVv(4z9InM_@ZvYDLL*zvI81uM298NgeR~>G_n9u@jFkMQ?c^QT9Ao&9j~Ex2Yle1 zi)K(`4|VtJ+At1T;_&=aTRn?p$R1YipH*jtjGzkG1&)gv1QuWbu7fSD3mf7htP=u@ zKyYZ)h{Jn2wLxJ0S<&&;*MR5Ah%ex!aB(-Tpg~rAByx=!TPMz0cL1xNx<(UC@jo;> z>N)^Tl%#)GT8G-{qn8DURY2YD;(z!e}Q?V=HEg#?m%r zvHP3OifP2G8`iLegbo|&)B}n#s!kPyYOzFmlQQ|Po}`8&FPluRrpdLm7^8}|S#_r^ zew>)aOqJU9X;*yf82A6#<%qTE_B0EyZtRl3tM&rEmD^Aje4c2@-<=PRycY}pv7&#h z41(|SM_(z_`+Q<|u@H(BLy_FnQK+}mk%}o%kzP2yAKg?7Q6#R??ArUtSR*H z%4h?s<&oF%d?13e;2kP@hw{xPFE5K&i@)|P-rUDsaRHuP8W-PoAo(Cow0;tid?pjE zUpP4s+7h?KgN|T)P&^n6a(*+I2#ALPKk~yX!NjO|IO;(j6&U~LS0CFuI7SMr3*p3j lJ7sEVo!(*m)5gCrb_4<2Amj+zx2vNpwGlkf-@rnc`x{=4Pvrmr literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/process_email_data/__pycache__/load_email_operators.cpython-312.pyc b/SMS-Exchange-Linux-GUI/process_email_data/__pycache__/load_email_operators.cpython-312.pyc new file mode 100755 index 0000000000000000000000000000000000000000..92a86ddb059db58c2a4f5862304d801a6b303452 GIT binary patch literal 1028 zcma)5O=uHA6n?X_X?B~R{-l^5S`tj5-9s8g1>1^{(pD-O4?&^5gk^Vaws^q>b11yAkOOF|EkH8)S*N+T57i!(7>!5{Pu`{tYX&HLV)-PwH!vlr*9mfV)Mrgub^7M?td=tEIkRA>Z8gV}C%R!fJxppwQ%qI+5f^7y6)kV;rXlgpP+qo| zGq#!0ad%LkKT zyc<5la6C8-cn|y(@A-q%5xf`iP%LqT-S+mG-$08(AidNb3zu`ITF7cw$N*ikf5{3^ SM{6VW8GJ3i8%ZQYBi{jqK=lFu literal 0 HcmV?d00001 diff --git a/SMS-Exchange-Linux-GUI/process_email_data/filter_email_names.py b/SMS-Exchange-Linux-GUI/process_email_data/filter_email_names.py new file mode 100755 index 0000000..a5672f4 --- /dev/null +++ b/SMS-Exchange-Linux-GUI/process_email_data/filter_email_names.py @@ -0,0 +1,10 @@ +# Convert it to lowercase and replace spaces with underscores to prevent SQL injections: +def filter_email_names(uppercase_chosen_email): + lowercase_raw_email = uppercase_chosen_email.lower() + + if lowercase_raw_email == "random email operator": + return "random" + if lowercase_raw_email == "no email" or lowercase_raw_email == "email disabled": + return "no" + else: + return lowercase_raw_email.replace(" ", "_") \ No newline at end of file diff --git a/SMS-Exchange-Linux-GUI/process_email_data/load_email_operators.py b/SMS-Exchange-Linux-GUI/process_email_data/load_email_operators.py new file mode 100755 index 0000000..06f8954 --- /dev/null +++ b/SMS-Exchange-Linux-GUI/process_email_data/load_email_operators.py @@ -0,0 +1,13 @@ +import json + +def load_email_operators(path_to_email_operators_list): + try: + with open(path_to_email_operators_list, 'r') as json_file: + data = json.load(json_file) + return data + except FileNotFoundError as e: + print(f"Error: {e}") + except json.JSONDecodeError as e: + print(f"Invalid JSON: {e}") + except Exception as e: + print(f"An error occurred: {e}") diff --git a/SMS-Exchange-Linux-GUI/requirements.txt b/SMS-Exchange-Linux-GUI/requirements.txt new file mode 100755 index 0000000..282130f --- /dev/null +++ b/SMS-Exchange-Linux-GUI/requirements.txt @@ -0,0 +1,19 @@ +aiohappyeyeballs==2.6.1 +aiohttp==3.13.3 +aiosignal==1.4.0 +asyncio==4.0.0 +attrs==25.4.0 +certifi==2026.1.4 +charset-normalizer==3.4.4 +frozenlist==1.8.0 +idna==3.11 +multidict==6.7.0 +propcache==0.4.1 +PyQt6==6.10.2 +PyQt6-Qt6==6.10.1 +PyQt6_sip==13.11.0 +qasync==0.28.0 +requests==2.32.5 +typing_extensions==4.15.0 +urllib3==2.6.3 +yarl==1.22.0