from core.Constants import Constants from core.models.Location import Location from core.models.Subscription import Subscription from core.models.session.ApplicationVersion import ApplicationVersion from dataclasses import dataclass, field, asdict from dataclasses_json import config, Exclude, dataclass_json from json import JSONDecodeError from typing import Optional, Self import json import os import re import shutil @dataclass_json @dataclass class BaseProfile: id: int = field( metadata=config(exclude=Exclude.ALWAYS) ) name: str subscription: Optional[Subscription] location: Optional[Location] def get_config_path(self): return BaseProfile.__get_config_path(self.id) def get_data_path(self): return BaseProfile.__get_data_path(self.id) def has_subscription(self): return self.subscription is not None def has_location(self): return self.location is not None def is_session_profile(self): return type(self).__name__ == 'SessionProfile' def is_system_profile(self): return type(self).__name__ == 'SystemProfile' def save(self: Self): config_file_contents = f'{self.to_json(indent=4)}\n' os.makedirs(self.get_config_path(), exist_ok=True) os.makedirs(self.get_data_path(), exist_ok=True) config_file_path = f'{self.get_config_path()}/config.json' with open(config_file_path, 'w') as config_file: config_file.write(config_file_contents) config_file.close() def delete_data(self): shutil.rmtree(self.get_data_path(), ignore_errors=True) def delete(self): shutil.rmtree(self.get_config_path(), ignore_errors=True) self.delete_data() def _get_dirty_keys(self: Self): reference = BaseProfile.find_by_id(self.id) if type(reference) != type(self): return list(self.__dataclass_fields__.keys()) return list([key for key, value in asdict(self).items() if value != asdict(reference).get(key)]) @staticmethod def find_by_id(id: int): try: config_file_contents = open(f'{BaseProfile.__get_config_path(id)}/config.json', 'r').read() except FileNotFoundError: return None try: profile = json.loads(config_file_contents) except JSONDecodeError: return None profile['id'] = id if profile['location'] is not None: location = Location.find(profile['location']['country_code'] or None, profile['location']['code'] or None) if location is not None: if profile['location'].get('time_zone') is not None: location.time_zone = profile['location']['time_zone'] profile['location'] = location if 'application_version' in profile: if profile['application_version'] is not None: application_version = ApplicationVersion.find(profile['application_version']['application_code'] or None, profile['application_version']['version_number'] or None) if application_version is not None: profile['application_version'] = application_version from core.models.session.SessionProfile import SessionProfile # noinspection PyUnresolvedReferences profile = SessionProfile.from_dict(profile) else: from core.models.system.SystemProfile import SystemProfile # noinspection PyUnresolvedReferences profile = SystemProfile.from_dict(profile) return profile @staticmethod def exists(id: int): return re.match(r'^\d{1,2}$', str(id)) and os.path.isfile(f'{BaseProfile.__get_config_path(id)}/config.json') @staticmethod def all(): profiles = {} for directory_entry in os.listdir(Constants.HV_PROFILE_CONFIG_HOME): try: id = int(directory_entry) except ValueError: continue if BaseProfile.exists(id): profile = BaseProfile.find_by_id(id) if profile is not None: profiles[id] = profile return dict(sorted(profiles.items())) @staticmethod def __get_config_path(id: int): return f'{Constants.HV_PROFILE_CONFIG_HOME}/{str(id)}' @staticmethod def __get_data_path(id: int): return f'{Constants.HV_PROFILE_DATA_HOME}/{str(id)}'