From 31a70eea5e6675af24d513e2e8bfe8dbf306fbf9 Mon Sep 17 00:00:00 2001 From: codeking Date: Mon, 3 Nov 2025 23:52:37 +0100 Subject: [PATCH] Implement support for location operators --- core/controllers/ClientController.py | 3 ++ core/controllers/OperatorController.py | 22 ++++++++++ core/models/Location.py | 15 ++++++- core/models/Operator.py | 56 ++++++++++++++++++++++++++ core/services/WebServiceApiService.py | 15 ++++++- 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 core/controllers/OperatorController.py create mode 100644 core/models/Operator.py diff --git a/core/controllers/ClientController.py b/core/controllers/ClientController.py index 97e216a..d47eb9e 100644 --- a/core/controllers/ClientController.py +++ b/core/controllers/ClientController.py @@ -5,6 +5,7 @@ from core.controllers.ApplicationVersionController import ApplicationVersionCont from core.controllers.ClientVersionController import ClientVersionController from core.controllers.ConfigurationController import ConfigurationController from core.controllers.LocationController import LocationController +from core.controllers.OperatorController import OperatorController from core.controllers.SubscriptionPlanController import SubscriptionPlanController from core.observers.ClientObserver import ClientObserver from core.observers.ConnectionObserver import ConnectionObserver @@ -73,6 +74,8 @@ class ClientController: # noinspection PyProtectedMember ClientVersionController._sync(proxies=proxies) # noinspection PyProtectedMember + OperatorController._sync(proxies=proxies) + # noinspection PyProtectedMember LocationController._sync(proxies=proxies) # noinspection PyProtectedMember SubscriptionPlanController._sync(proxies=proxies) diff --git a/core/controllers/OperatorController.py b/core/controllers/OperatorController.py new file mode 100644 index 0000000..9d54c4a --- /dev/null +++ b/core/controllers/OperatorController.py @@ -0,0 +1,22 @@ +from core.models.Operator import Operator +from core.services.WebServiceApiService import WebServiceApiService +from typing import Optional + + +class OperatorController: + + @staticmethod + def get(id: int): + return Operator.find_by_id(id) + + @staticmethod + def get_all(): + return Operator.all() + + @staticmethod + def _sync(proxies: Optional[dict] = None): + + operators = WebServiceApiService.get_operators(proxies) + + Operator.truncate() + Operator.save_many(operators) diff --git a/core/models/Location.py b/core/models/Location.py index 3b3c06d..89c23d5 100644 --- a/core/models/Location.py +++ b/core/models/Location.py @@ -1,4 +1,5 @@ from core.models.Model import Model +from core.models.Operator import Operator from dataclasses import dataclass, field from dataclasses_json import config, Exclude from typing import Optional @@ -12,6 +13,7 @@ _table_definition: str = """ 'code' varchar, 'name' varchar, 'time_zone' varchar, + 'operator_id' int, 'provider_name' varchar, UNIQUE(code, country_code) """ @@ -34,16 +36,25 @@ class Location(Model): metadata=config(exclude=Exclude.ALWAYS) ) time_zone: Optional[str] = None + operator_id: Optional[int] = field( + default=None, + metadata=config(exclude=Exclude.ALWAYS) + ) provider_name: Optional[str] = field( default=None, metadata=config(exclude=Exclude.ALWAYS) ) + operator: Optional[Operator] = field( + default=None, + metadata=config(exclude=Exclude.ALWAYS) + ) available: Optional[bool] = field( default=False, metadata=config(exclude=Exclude.ALWAYS) ) def __post_init__(self): + self.operator = Operator.find_by_id(self.operator_id) self.available = self.exists(self.country_code, self.code) def is_available(self): @@ -76,7 +87,7 @@ class Location(Model): @staticmethod def save_many(locations): Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition) - Model._insert_many('INSERT INTO locations VALUES(?, ?, ?, ?, ?, ?, ?)', Location.tuple_factory, locations) + Model._insert_many('INSERT INTO locations VALUES(?, ?, ?, ?, ?, ?, ?, ?)', Location.tuple_factory, locations) @staticmethod def factory(cursor, row): @@ -85,4 +96,4 @@ class Location(Model): @staticmethod def tuple_factory(location): - return location.id, location.country_code, location.country_name, location.code, location.name, location.time_zone, location.provider_name + return location.id, location.country_code, location.country_name, location.code, location.name, location.time_zone, location.operator_id, location.provider_name diff --git a/core/models/Operator.py b/core/models/Operator.py new file mode 100644 index 0000000..8ad7856 --- /dev/null +++ b/core/models/Operator.py @@ -0,0 +1,56 @@ +from core.models.Model import Model +from dataclasses import dataclass + +_table_name: str = 'operators' + +_table_definition: str = """ + 'id' int UNIQUE, + 'name' varchar, + 'public_key' varchar, + 'nostr_public_key' varchar, + 'nostr_profile_reference' varchar, + 'nostr_attestation_event_reference' varchar +""" + + +@dataclass +class Operator(Model): + id: int + name: str + public_key: str + nostr_public_key: str + nostr_profile_reference: str + nostr_attestation_event_reference: str + + @staticmethod + def find_by_id(id: int): + Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition) + return Model._query_one('SELECT * FROM operators WHERE id = ? LIMIT 1', Operator.factory, [id]) + + @staticmethod + def exists(id: int): + Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition) + return Model._query_exists('SELECT * FROM operators WHERE id = ?', [id]) + + @staticmethod + def all(): + Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition) + return Model._query_all('SELECT * FROM operators', Operator.factory) + + @staticmethod + def truncate(): + Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition, drop_existing=True) + + @staticmethod + def save_many(operators): + Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition) + Model._insert_many('INSERT INTO operators VALUES(?, ?, ?, ?, ?, ?)', Operator.tuple_factory, operators) + + @staticmethod + def factory(cursor, row): + local_fields = [column[0] for column in cursor.description] + return Operator(**{key: value for key, value in zip(local_fields, row)}) + + @staticmethod + def tuple_factory(operator): + return operator.id, operator.name, operator.public_key, operator.nostr_public_key, operator.nostr_profile_reference, operator.nostr_attestation_event_reference diff --git a/core/services/WebServiceApiService.py b/core/services/WebServiceApiService.py index c86ed59..d91435c 100644 --- a/core/services/WebServiceApiService.py +++ b/core/services/WebServiceApiService.py @@ -1,6 +1,7 @@ from core.Constants import Constants from core.models.ClientVersion import ClientVersion from core.models.Location import Location +from core.models.Operator import Operator from core.models.Subscription import Subscription from core.models.SubscriptionPlan import SubscriptionPlan from core.models.invoice.Invoice import Invoice @@ -51,6 +52,18 @@ class WebServiceApiService: return client_versions + @staticmethod + def get_operators(proxies: Optional[dict] = None): + + response = WebServiceApiService.__get('/operators', None, proxies) + operators = [] + + if response.status_code == requests.codes.ok: + for operator in response.json()['data']: + operators.append(Operator(operator['id'], operator['name'], operator['public_key'], operator['nostr_public_key'], operator['nostr_profile_reference'], operator['nostr_attestation']['event_reference'])) + + return operators + @staticmethod def get_locations(proxies: Optional[dict] = None): @@ -59,7 +72,7 @@ class WebServiceApiService: if response.status_code == requests.codes.ok: for location in response.json()['data']: - locations.append(Location(location['country']['code'], location['code'], location['id'], location['country']['name'], location['name'], location['time_zone']['code'], location['provider']['name'])) + locations.append(Location(location['country']['code'], location['code'], location['id'], location['country']['name'], location['name'], location['time_zone']['code'], location['operator']['id'], location['provider']['name'])) return locations