diff --git a/Pipfile b/Pipfile index 578293c..6c9cf53 100644 --- a/Pipfile +++ b/Pipfile @@ -12,6 +12,7 @@ django-bootstrap4 = "*" django-invitations = "*" django-hashid-field = "*" frozendict = "*" +django-guardian = "*" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index 559de0b..4ebd40e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "36bd6ea9711c247710904103a81d2a2abae1000e988ebee11d5eaa22697d5cdf" + "sha256": "c64de64f000ab3904d359eac1b8e630940fa6d7baa0447215243b565ae03c82d" }, "pipfile-spec": 6, "requires": { @@ -40,20 +40,28 @@ "index": "pypi", "version": "==1.1.1" }, - "django-hashid-field": { + "django-guardian": { "hashes": [ - "sha256:328e83f13ab0eedd4ed8a384bde8b7a4ce18ee8ee1e1d149247ba7611fc7addb", - "sha256:cff0805a4c4243d1c30d180e70efbe08395bddce4177d4c968c1f9bf0542a5a5" + "sha256:8cacf49ebcc1e545f0a8997971eec0fe109f5ed31fc2a569a7bf5615453696e2", + "sha256:ac81e88372fdf1795d84ba065550e739b42e9c6d07cdf201cf5bbf9efa7f396c" ], "index": "pypi", - "version": "==3.0.0" + "version": "==2.2.0" + }, + "django-hashid-field": { + "hashes": [ + "sha256:98096dc25ee558cd26628b33149da2d74722c925aa484c12347d75e6df2a1d19", + "sha256:a28b99fc779c62cbd42e910809db063841f055db37424b644127134d17631339" + ], + "index": "pypi", + "version": "==3.1.1" }, "django-invitations": { "hashes": [ - "sha256:fe0a4c822bf695f7dac9f828c95f1dcee42dc590ed2943bd4d6ec8a1e03ab08e" + "sha256:6077807aa641c7abae9ca418e757c8e3940fb0ce60499dba24c100ad57c61442" ], "index": "pypi", - "version": "==1.9.2" + "version": "==1.9.3" }, "frozendict": { "hashes": [ @@ -77,17 +85,17 @@ }, "soupsieve": { "hashes": [ - "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5", - "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda" + "sha256:e914534802d7ffd233242b785229d5ba0766a7f487385e3f714446a07bf540ae", + "sha256:fcd71e08c0aee99aca1b73f45478549ee7e7fc006d51b37bec9e9def7dc22b69" ], - "version": "==1.9.5" + "version": "==2.0" }, "sqlparse": { "hashes": [ - "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", - "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" + "sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e", + "sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548" ], - "version": "==0.3.0" + "version": "==0.3.1" } }, "develop": { @@ -115,10 +123,10 @@ }, "click": { "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc", + "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a" ], - "version": "==7.0" + "version": "==7.1.1" }, "pathspec": { "hashes": [ @@ -129,29 +137,29 @@ }, "regex": { "hashes": [ - "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525", - "sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b", - "sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576", - "sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5", - "sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0", - "sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35", - "sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003", - "sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d", - "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161", - "sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26", - "sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9", - "sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1", - "sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146", - "sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f", - "sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149", - "sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351", - "sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461", - "sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b", - "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242", - "sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c", - "sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77" + "sha256:01b2d70cbaed11f72e57c1cfbaca71b02e3b98f739ce33f5f26f71859ad90431", + "sha256:046e83a8b160aff37e7034139a336b660b01dbfe58706f9d73f5cdc6b3460242", + "sha256:113309e819634f499d0006f6200700c8209a2a8bf6bd1bdc863a4d9d6776a5d1", + "sha256:200539b5124bc4721247a823a47d116a7a23e62cc6695744e3eb5454a8888e6d", + "sha256:25f4ce26b68425b80a233ce7b6218743c71cf7297dbe02feab1d711a2bf90045", + "sha256:269f0c5ff23639316b29f31df199f401e4cb87529eafff0c76828071635d417b", + "sha256:5de40649d4f88a15c9489ed37f88f053c15400257eeb18425ac7ed0a4e119400", + "sha256:7f78f963e62a61e294adb6ff5db901b629ef78cb2a1cfce3cf4eeba80c1c67aa", + "sha256:82469a0c1330a4beb3d42568f82dffa32226ced006e0b063719468dcd40ffdf0", + "sha256:8c2b7fa4d72781577ac45ab658da44c7518e6d96e2a50d04ecb0fd8f28b21d69", + "sha256:974535648f31c2b712a6b2595969f8ab370834080e00ab24e5dbb9d19b8bfb74", + "sha256:99272d6b6a68c7ae4391908fc15f6b8c9a6c345a46b632d7fdb7ef6c883a2bbb", + "sha256:9b64a4cc825ec4df262050c17e18f60252cdd94742b4ba1286bcfe481f1c0f26", + "sha256:9e9624440d754733eddbcd4614378c18713d2d9d0dc647cf9c72f64e39671be5", + "sha256:9ff16d994309b26a1cdf666a6309c1ef51ad4f72f99d3392bcd7b7139577a1f2", + "sha256:b33ebcd0222c1d77e61dbcd04a9fd139359bded86803063d3d2d197b796c63ce", + "sha256:bba52d72e16a554d1894a0cc74041da50eea99a8483e591a9edf1025a66843ab", + "sha256:bed7986547ce54d230fd8721aba6fd19459cdc6d315497b98686d0416efaff4e", + "sha256:c7f58a0e0e13fb44623b65b01052dae8e820ed9b8b654bb6296bc9c41f571b70", + "sha256:d58a4fa7910102500722defbde6e2816b0372a4fcc85c7e239323767c74f5cbc", + "sha256:f1ac2dc65105a53c1c2d72b1d3e98c2464a133b4067a51a3d2477b28449709a0" ], - "version": "==2020.1.8" + "version": "==2020.2.20" }, "toml": { "hashes": [ @@ -162,28 +170,29 @@ }, "typed-ast": { "hashes": [ - "sha256:1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", - "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", - "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", - "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", - "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", - "sha256:48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", - "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", - "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", - "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", - "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", - "sha256:7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", - "sha256:838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", - "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", - "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", - "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", - "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", - "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", - "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", - "sha256:fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", - "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" ], - "version": "==1.4.0" + "version": "==1.4.1" } } } diff --git a/market/settings/common.py b/market/settings/common.py index 283f167..f8fcf2b 100644 --- a/market/settings/common.py +++ b/market/settings/common.py @@ -51,10 +51,12 @@ INSTALLED_APPS = [ # Third party apps "bootstrap4", + "guardian", ] AUTHENTICATION_BACKENDS = [ "django.contrib.auth.backends.ModelBackend", + "guardian.backends.ObjectPermissionBackend", ] MIDDLEWARE = [ diff --git a/static/trading/css/trading.css b/static/trading/css/trading.css new file mode 100644 index 0000000..1072f6b --- /dev/null +++ b/static/trading/css/trading.css @@ -0,0 +1,17 @@ +.debit { + color: red; + /*font-weight: bold;*/ +} + +.debit:before { + content: "("; +} + +.debit:after { + content: ")"; +} + +.credit { + color: black; + /*font-weight: bold;*/ +} diff --git a/trading/migrations/0001_initial.py b/trading/migrations/0001_initial.py index ea7df37..d654117 100644 --- a/trading/migrations/0001_initial.py +++ b/trading/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2 on 2020-01-17 01:24 +# Generated by Django 2.2 on 2020-03-21 18:57 from django.conf import settings from django.db import migrations, models @@ -58,12 +58,12 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('status', models.CharField(choices=[('OPEN', 'Open'), ('DECL', 'Declined'), ('ACC', 'Accepted')], default='OPEN', max_length=2)), - ('source_amount', models.PositiveIntegerField()), - ('dest_amount', models.PositiveIntegerField()), - ('dest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transaction_requests_received', to=settings.AUTH_USER_MODEL)), - ('dest_sends', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='trading.Commodity')), - ('source', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transaction_requests_sent', to=settings.AUTH_USER_MODEL)), - ('source_sends', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='trading.Commodity')), + ('source_amount', models.PositiveIntegerField(editable=False)), + ('dest_amount', models.PositiveIntegerField(editable=False)), + ('dest', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='transaction_requests_received', to=settings.AUTH_USER_MODEL)), + ('dest_sends', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='trading.Commodity')), + ('source', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='transaction_requests_sent', to=settings.AUTH_USER_MODEL)), + ('source_sends', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='trading.Commodity')), ], ), migrations.CreateModel( diff --git a/trading/models.py b/trading/models.py index f0069df..f274ff6 100644 --- a/trading/models.py +++ b/trading/models.py @@ -7,6 +7,7 @@ from django.db.models.signals import post_save, pre_save from django.dispatch import receiver from django.utils.translation import gettext_lazy as _ from frozendict import frozendict +from guardian.shortcuts import assign_perm from hashid_field import HashidAutoField from trading.managers import UserManager @@ -89,9 +90,9 @@ class User(PermissionsMixin, AbstractBaseUser): } tx_requests = { row["source_sends"]: row["source_amount__sum"] - for row in self.transaction_requests_sent.filter( - status=TxRequest.OPEN - ).values("source_sends").annotate(Sum("source_amount")) + for row in self.transaction_requests_sent.filter(status=TxRequest.OPEN) + .values("source_sends") + .annotate(Sum("source_amount")) } keys = ( set(ipos.keys()) @@ -244,21 +245,27 @@ class TxRequest(models.Model): # ) source = models.ForeignKey( - User, on_delete=models.CASCADE, related_name="transaction_requests_sent", + User, + on_delete=models.CASCADE, + related_name="transaction_requests_sent", + editable=False, ) dest = models.ForeignKey( - User, on_delete=models.CASCADE, related_name="transaction_requests_received", + User, + on_delete=models.CASCADE, + related_name="transaction_requests_received", + editable=False, ) source_sends = models.ForeignKey( - Commodity, on_delete=models.CASCADE, related_name="+", null=True, + Commodity, on_delete=models.CASCADE, related_name="+", null=True, editable=False, ) dest_sends = models.ForeignKey( - Commodity, on_delete=models.CASCADE, related_name="+", null=True, + Commodity, on_delete=models.CASCADE, related_name="+", null=True, editable=False, ) - source_amount = models.PositiveIntegerField() - dest_amount = models.PositiveIntegerField() + source_amount = models.PositiveIntegerField(editable=False) + dest_amount = models.PositiveIntegerField(editable=False) @staticmethod def open( @@ -275,7 +282,9 @@ class TxRequest(models.Model): # Check balance source_balance = source.balance_of(source_sends) if source_balance < source_amount: - raise BalanceError(source_balance, source, dest, source_amount, source_sends) + raise BalanceError( + source_balance, source, dest, source_amount, source_sends + ) req = TxRequest.objects.create( status=TxRequest.OPEN, source=source, @@ -288,20 +297,28 @@ class TxRequest(models.Model): req.save() return req + def can_accept(self) -> bool: + """ + Gets whether this request can be accepted. + """ + dest_balance = self.dest.balance_of(self.dest_sends) + return self.status == TxRequest.OPEN and dest_balance >= self.dest_amount + + def accept(self): """ Accepts an open transaction request. """ assert self.status == TxRequest.OPEN - # ensure destination balance before continuing - dest_balance = self.dest.balance_of(self.dest_sends) - if dest_balance < self.dest_amount: + # Ensure destination balance before continuing + if not self.can_accept(): + dest_balance = self.dest.balance_of(self.dest_sends) raise BalanceError( dest_balance, self.dest, self.source, self.dest_amount, self.dest_sends ) - # update status + # Update status self.status = TxRequest.ACCEPTED # Create source transaction @@ -336,6 +353,8 @@ class TxRequest(models.Model): self.save() + + class BalanceError(Exception): def __init__( self, balance: int, source: User, dest: User, amount: int, commodity: Commodity @@ -364,3 +383,11 @@ def _tx_pre_save(sender, instance, *args, **kwargs): instance.amount, instance.commodity, ) + + +@receiver(post_save, sender=TxRequest) +def __tx_post_save(sender, instance, created, **kwargs): + if not created: + return + assign_perm("view_txrequest", instance.source, instance) + assign_perm("view_txrequest", instance.dest, instance) diff --git a/trading/templates/trading/base.html b/trading/templates/trading/base.html index 842383e..7b09675 100644 --- a/trading/templates/trading/base.html +++ b/trading/templates/trading/base.html @@ -7,6 +7,7 @@ + {% block title %}Trading{% if title %} - {{ title }}{% endif %}{% endblock title %} diff --git a/trading/templates/trading/r/detail.html b/trading/templates/trading/r/detail.html new file mode 100644 index 0000000..b2cf5ae --- /dev/null +++ b/trading/templates/trading/r/detail.html @@ -0,0 +1,42 @@ +{% extends "trading/base.html" %} +{% load bootstrap4 %} +{% load humanize %} + +{% block title %} + {% with title="Transaction request detail" %} + {{ block.super }} + {% endwith %} +{% endblock title %} + +{% block content %} +
+
+ + + + + + + + + + + + + + + + + +
CommodityAmount
{{ object.source_sends.name }} + + {{object.source_amount|intcomma}} + +
{{ object.dest_sends.name }} + + {{object.dest_amount|intcomma}} + +
+
+
+{% endblock %} diff --git a/trading/templates/trading/t/detail.html b/trading/templates/trading/t/detail.html new file mode 100644 index 0000000..a0aec43 --- /dev/null +++ b/trading/templates/trading/t/detail.html @@ -0,0 +1,34 @@ +{% extends "trading/base.html" %} +{% load bootstrap4 %} +{% load humanize %} + +{% block title %} + {% with title="Transaction detail" %} + {{ block.super }} + {% endwith %} +{% endblock title %} + +{% block content %} +
+
+ + + + + + + + + + + + + +
CommodityDelta
{{ object.commodity.name }} + + {{object.amount|intcomma}} + +
+
+
+{% endblock %} diff --git a/trading/templates/trading/t/list.html b/trading/templates/trading/t/list.html new file mode 100644 index 0000000..d48ec91 --- /dev/null +++ b/trading/templates/trading/t/list.html @@ -0,0 +1,43 @@ +{% extends "trading/base.html" %} +{% load bootstrap4 %} +{% load humanize %} + +{% block title %} + {% with title="Transaction detail" %} + {{ block.super }} + {% endwith %} +{% endblock title %} + +{% block content %} +
+
+ + + + + + + + + + + + {% for object in object_list %} + + + + + + + + {% endfor %} + +
CommodityDeltaStatusSourceDestination
{{ object.commodity.name }} + + {{object.amount|intcomma}} + + {{object.status}}{{object.source.username}}{{object.dest.username}}
+
+
+{% endblock %} + diff --git a/trading/urls.py b/trading/urls.py index c779ccc..355bd09 100644 --- a/trading/urls.py +++ b/trading/urls.py @@ -69,6 +69,9 @@ urlpatterns = [ path("u/profile//", UserProfileView.as_view(), name="user_profile"), # t/ for tx + path("t/detail//", TxRequestDetailView.as_view(), name="tx_detail"), + path("t/", TxRequestListView.as_view(), name="tx_list"), + # c/ for commodities path("c/create/", CommodityCreateView.as_view(), name="commodity_create"), diff --git a/trading/views.py b/trading/views.py index 68599bc..7c383c2 100644 --- a/trading/views.py +++ b/trading/views.py @@ -1,22 +1,28 @@ from django import forms from django.contrib.auth import views as auth_views, password_validation from django.contrib.auth.forms import UsernameField -from django.contrib.auth.mixins import LoginRequiredMixin +from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.contrib import messages from django.core.exceptions import PermissionDenied +from django.db.models import Q from django.http import HttpResponseForbidden, HttpResponseRedirect from django.views.generic import TemplateView from django.views.generic.detail import DetailView from django.views.generic.edit import CreateView, UpdateView +from django.views.generic.list import ListView from django.urls import reverse, reverse_lazy from django.utils.translation import gettext_lazy as _ -from trading.models import User, Commodity, MaxCommodityError +from trading.models import User, Commodity, MaxCommodityError, Tx, TxRequest class IndexView(LoginRequiredMixin, TemplateView): template_name = "trading/index.html" +################################################################################ +# Commodity views +################################################################################ + class CommodityDetailView(DetailView): template_name = "trading/c/detail.html" model = Commodity @@ -43,6 +49,29 @@ class CommodityCreateView(LoginRequiredMixin, CreateView): return super(CreateView, self).form_valid(form) +################################################################################ +# Tx views +################################################################################ + +class TxRequestDetailView(DetailView): + template_name = "trading/t/detail.html" + model = TxRequest + + +class TxRequestListView(LoginRequiredMixin, ListView): + template_name = "trading/t/list.html" + model = TxRequest + paginate_by = 100 + + def get_queryset(self): + user = self.request.user + return TxRequest.objects.filter(Q(source=user) | Q(dest=user)).order_by("-pk") + + +################################################################################ +# User views +################################################################################ + class UserProfileView(DetailView): template_name = "trading/u/profile.html" model = User @@ -78,3 +107,4 @@ class UserSettingsView(LoginRequiredMixin, UpdateView): def get_object(self, queryset=None): return self.request.user +