From 0723f14c532ed670f6f4e0e3e907113dce85f2d7 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Fri, 17 Mar 2023 18:37:38 +0000 Subject: [PATCH] Implement wallet model and CRUD --- app/urls.py | 32 ++++++++- core/forms.py | 42 +++++++++-- ...oughput_wallet_platform_payees_and_more.py | 39 +++++++++++ ...29_alter_requisition_id_alter_wallet_id.py | 25 +++++++ core/models.py | 28 ++++---- core/templates/base.html | 3 + core/templates/partials/ad-list.html | 2 +- core/templates/partials/wallet-list.html | 69 +++++++++++++++++++ core/views/wallets.py | 35 ++++++++++ 9 files changed, 256 insertions(+), 19 deletions(-) create mode 100644 core/migrations/0028_requisition_throughput_wallet_platform_payees_and_more.py create mode 100644 core/migrations/0029_alter_requisition_id_alter_wallet_id.py create mode 100644 core/templates/partials/wallet-list.html create mode 100644 core/views/wallets.py diff --git a/app/urls.py b/app/urls.py index d61ca73..3f99600 100644 --- a/app/urls.py +++ b/app/urls.py @@ -20,7 +20,16 @@ from django.contrib.auth.views import LogoutView from django.urls import include, path from two_factor.urls import urlpatterns as tf_urls -from core.views import ads, aggregators, banks, base, notifications, platforms, profit +from core.views import ( + ads, + aggregators, + banks, + base, + notifications, + platforms, + profit, + wallets, +) # from core.views.stripe_callbacks import Callback @@ -200,4 +209,25 @@ urlpatterns = [ profit.Profit.as_view(), name="profit", ), + # Wallets + path( + "wallets//", + wallets.WalletList.as_view(), + name="wallets", + ), + path( + "wallets//create/", + wallets.WalletCreate.as_view(), + name="wallet_create", + ), + path( + "wallets//update//", + wallets.WalletUpdate.as_view(), + name="wallet_update", + ), + path( + "wallets//delete//", + wallets.WalletDelete.as_view(), + name="wallet_delete", + ), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/core/forms.py b/core/forms.py index 8822bbe..af7ac22 100644 --- a/core/forms.py +++ b/core/forms.py @@ -13,6 +13,7 @@ from .models import ( Provider, Requisition, User, + Wallet, ) # flake8: noqa: E501 @@ -90,10 +91,11 @@ class PlatformForm(RestrictedFormMixin, ModelForm): upper = ["usd", "otp"] for field in self.fields: for up in upper: - if up in self.fields[field].label: - self.fields[field].label = self.fields[field].label.replace( - up, up.upper() - ) + if self.fields[field].label: + if up in self.fields[field].label: + self.fields[field].label = self.fields[field].label.replace( + up, up.upper() + ) class Meta: model = Platform @@ -117,6 +119,7 @@ class PlatformForm(RestrictedFormMixin, ModelForm): "no_reference_amount_check_max_usd", "base_usd", "withdrawal_trigger", + "payees", "enabled", ) help_texts = { @@ -139,9 +142,17 @@ class PlatformForm(RestrictedFormMixin, ModelForm): "no_reference_amount_check_max_usd": "When ticked, when no reference was found and a trade is higher than this amount, we will not accept payment even if it is the only one with this amount.", "base_usd": "The amount in USD to keep in the platform.", "withdrawal_trigger": "The amount above the base USD to trigger a withdrawal.", + "payees": "The wallet addresses to send profit concerning this platform to.", "enabled": "Whether or not the platform connection is enabled.", } + payees = forms.ModelMultipleChoiceField( + queryset=Wallet.objects.all(), + widget=forms.CheckboxSelectMultiple, + help_text=Meta.help_texts["payees"], + required=False, + ) + class AdForm(RestrictedFormMixin, ModelForm): def __init__(self, *args, **kwargs): @@ -214,9 +225,32 @@ class RequisitionForm(RestrictedFormMixin, ModelForm): fields = ( "payment_details", "transaction_source", + "payees", ) help_texts = { "payment_details": "Shown once a user opens a trade.", "transaction_source": "Whether to check pending or booked transactions.", + "payees": "The wallet addresses to send profit concerning this requisition to.", + } + + payees = forms.ModelMultipleChoiceField( + queryset=Wallet.objects.all(), + widget=forms.CheckboxSelectMultiple, + help_text=Meta.help_texts["payees"], + required=False, + ) + + +class WalletForm(RestrictedFormMixin, ModelForm): + class Meta: + model = Wallet + fields = ( + "name", + "address", + ) + + help_texts = { + "name": "The name of the wallet.", + "address": "The XMR address to send funds to.", } diff --git a/core/migrations/0028_requisition_throughput_wallet_platform_payees_and_more.py b/core/migrations/0028_requisition_throughput_wallet_platform_payees_and_more.py new file mode 100644 index 0000000..d4cb284 --- /dev/null +++ b/core/migrations/0028_requisition_throughput_wallet_platform_payees_and_more.py @@ -0,0 +1,39 @@ +# Generated by Django 4.1.7 on 2023-03-17 18:15 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0027_alter_requisition_payment_details'), + ] + + operations = [ + migrations.AddField( + model_name='requisition', + name='throughput', + field=models.FloatField(default=0), + ), + migrations.CreateModel( + name='Wallet', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('address', models.CharField(max_length=255)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AddField( + model_name='platform', + name='payees', + field=models.ManyToManyField(blank=True, to='core.wallet'), + ), + migrations.AddField( + model_name='requisition', + name='payees', + field=models.ManyToManyField(blank=True, to='core.wallet'), + ), + ] diff --git a/core/migrations/0029_alter_requisition_id_alter_wallet_id.py b/core/migrations/0029_alter_requisition_id_alter_wallet_id.py new file mode 100644 index 0000000..78b7d16 --- /dev/null +++ b/core/migrations/0029_alter_requisition_id_alter_wallet_id.py @@ -0,0 +1,25 @@ +# Generated by Django 4.1.7 on 2023-03-17 18:31 + +import uuid + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0028_requisition_throughput_wallet_platform_payees_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='requisition', + name='id', + field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='wallet', + name='id', + field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), + ), + ] diff --git a/core/models.py b/core/models.py index ccdb32b..b09c154 100644 --- a/core/models.py +++ b/core/models.py @@ -158,6 +158,17 @@ class Aggregator(models.Model): return transaction +class Wallet(models.Model): + """ + A wallet for a user. + """ + + 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) + address = models.CharField(max_length=255) + + class Platform(models.Model): """ A connection to an arbitrage platform like AgoraDesk. @@ -192,7 +203,7 @@ class Platform(models.Model): base_usd = models.FloatField(default=2800) withdrawal_trigger = models.FloatField(default=200) - # payees = models.ManyToManyField(Wallet, blank=True) + payees = models.ManyToManyField(Wallet, blank=True) enabled = models.BooleanField(default=True) @@ -488,21 +499,12 @@ class Trade(models.Model): release_response = models.JSONField(default=dict) -# class BankAccount(models.Model): -# """ -# Extra information for an account. -# """ -# account_id = models.CharField(max_length=255) -# payment_details = models.TextField() - -# enabled = models.BooleanField(default=True) - - class Requisition(models.Model): """ A requisition for an Aggregator """ + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE) aggregator = models.ForeignKey(Aggregator, on_delete=models.CASCADE) requisition_id = models.CharField(max_length=255) @@ -512,8 +514,8 @@ class Requisition(models.Model): max_length=255, choices=TRANSACTION_SOURCE_CHOICES, default="booked" ) - # throughput = models.FloatField(default=0) - # payees = models.ManyToManyField(Wallet, blank=True) + throughput = models.FloatField(default=0) + payees = models.ManyToManyField(Wallet, blank=True) assets = { diff --git a/core/templates/base.html b/core/templates/base.html index b7a4c7a..2b64b91 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -271,6 +271,9 @@ Platform Connections + + Wallets +