import uuid from django.contrib.auth.models import AbstractUser from django.db import models # from core.lib.customers import get_or_create, update_customer_fields from core.util import logs log = logs.get_logger(__name__) SERVICE_CHOICES = (("nordigen", "Nordigen"),) PLATFORM_SERVICE_CHOICES = (("agora", "Agora"),) INTERVAL_CHOICES = ( (60, "Every minute"), (60 * 5, "Every 5 minutes"), (60 * 10, "Every 10 minutes"), (60 * 60, "Every hour"), (60 * 60 * 4, "Every 4 hours"), (86400, "Every day"), ) class User(AbstractUser): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) payment_provider_id = models.CharField(max_length=255, null=True, blank=True) billing_provider_id = models.CharField(max_length=255, null=True, blank=True) email = models.EmailField(unique=True) def get_notification_settings(self): return NotificationSettings.objects.get_or_create(user=self)[0] class NotificationSettings(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) ntfy_topic = models.CharField(max_length=255, null=True, blank=True) ntfy_url = models.CharField(max_length=255, null=True, blank=True) def __str__(self): return f"Notification settings for {self.user}" class Aggregator(models.Model): """ A connection to an API aggregator to pull transactions from bank accounts. """ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE) name = models.CharField(max_length=255) service = models.CharField(max_length=255, choices=SERVICE_CHOICES) secret_id = models.CharField(max_length=1024, null=True, blank=True) secret_key = models.CharField(max_length=1024, null=True, blank=True) access_token = models.CharField(max_length=1024, null=True, blank=True) access_token_expires = models.DateTimeField(null=True, blank=True) poll_interval = models.IntegerField(default=10) account_info = models.JSONField(default=dict) currencies = models.JSONField(default=list) fetch_accounts = models.BooleanField(default=True) enabled = models.BooleanField(default=True) def __str__(self): return f"{self.name} ({self.get_service_display()})" @classmethod def get_by_id(cls, obj_id, user): return cls.objects.get(id=obj_id, user=user) @property def client(self): pass @classmethod def get_for_platform(cls, platform): return cls.objects.filter(user=platform.user, enabled=True) @classmethod def get_currencies_for_platform(cls, platform): aggregators = Aggregator.get_for_platform(platform) currencies = set() for aggregator in aggregators: for currency in aggregator.currencies: currencies.add(currency) return list(currencies) @classmethod def get_account_info_for_platform(cls, platform): aggregators = Aggregator.get_for_platform(platform) account_info = {} for agg in aggregators: for bank, accounts in agg.account_info.items(): if bank not in account_info: account_info[bank] = [] for account in accounts: account_info[bank].append(account) return account_info class Platform(models.Model): """ A connection to an arbitrage platform like AgoraDesk. """ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE) name = models.CharField(max_length=255) service = models.CharField(max_length=255, choices=PLATFORM_SERVICE_CHOICES) token = models.CharField(max_length=1024) password = models.CharField(max_length=1024) otp_token = models.CharField(max_length=1024, null=True, blank=True) username = models.CharField(max_length=255) send = models.BooleanField(default=True) cheat = models.BooleanField(default=False) dummy = models.BooleanField(default=False) cheat_interval_seconds = models.IntegerField(default=3600, choices=INTERVAL_CHOICES) margin = models.FloatField(default=1.20) max_margin = models.FloatField(default=1.30) min_margin = models.FloatField(default=1.15) min_trade_size_usd = models.FloatField(default=10) max_trade_size_usd = models.FloatField(default=4000) accept_within_usd = models.FloatField(default=1) no_reference_amount_check_max_usd = models.FloatField(default=400) last_messages = models.JSONField(default=dict) platform_ad_ids = models.JSONField(default=dict) base_usd = models.FloatField(default=2800) withdrawal_trigger = models.FloatField(default=200) enabled = models.BooleanField(default=True) def __str__(self): return self.name def get_ad(self, platform_ad_id): ad_id = self.platform_ad_ids.get(platform_ad_id, None) if not ad_id: return None ad_object = Ad.objects.filter(id=ad_id, user=self.user, enabled=True).first() return ad_object @classmethod def get_for_user(cls, user): return cls.objects.filter(user=user, enabled=True) @property def currencies(self): return Aggregator.get_currencies_for_platform(self) @property def account_info(self): return Aggregator.get_account_info_for_platform(self) @property def ads(self): """ Get all ads linked to this platform. """ return Ad.objects.filter(user=self.user, enabled=True, platforms=self) @property def ads_assets(self): """ Get all the assets of all the ads. """ assets = set() for ad in self.ads: for asset in ad.asset_list.all(): assets.add(asset.code) return list(assets) @property def ads_providers(self): """ Get all the providers of all the ads. """ providers = set() for ad in self.ads: for provider in ad.provider_list.all(): providers.add(provider.code) return list(providers) class Asset(models.Model): code = models.CharField(max_length=64) name = models.CharField(max_length=255) def __str__(self): return f"{self.name} ({self.code})" class Provider(models.Model): code = models.CharField(max_length=64) name = models.CharField(max_length=255) def __str__(self): return f"{self.name} ({self.code})" class Ad(models.Model): """ An advert definition """ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE) name = models.CharField(max_length=255) text = models.TextField() # Shown when the user opens a trade payment_details = models.TextField() # Shown after payment_details_real = models.TextField() payment_method_details = models.CharField(max_length=255) dist_list = models.TextField() asset_list = models.ManyToManyField(Asset) provider_list = models.ManyToManyField(Provider) platforms = models.ManyToManyField(Platform) aggregators = models.ManyToManyField(Aggregator) account_map = models.JSONField(default=dict) account_whitelist = models.TextField(null=True, blank=True) visible = models.BooleanField(default=True) enabled = models.BooleanField(default=True) @classmethod def get_by_id(cls, ad_id, user): return cls.objects.filter(id=ad_id, user=user, enabled=True).first() assets = { "XMR": "Monero", "BTC": "Bitcoin", } providers = { "REVOLUT": "Revolut", "NATIONAL_BANK": "Bank transfer", "SWISH": "Swish", } for code, name in assets.items(): if not Asset.objects.filter(code=code).exists(): Asset.objects.create(code=code, name=name) for code, name in providers.items(): if not Provider.objects.filter(code=code).exists(): Provider.objects.create(code=code, name=name)