From 0175e73ca186ff9aea5ed1051e0fc194a0ee41b1 Mon Sep 17 00:00:00 2001 From: KoalaSat Date: Fri, 28 Jun 2024 15:56:58 +0200 Subject: [PATCH] New notifications --- api/admin.py | 2 ++ api/models/order.py | 8 +++--- api/notifications.py | 44 +++++++++++++++++++++++++++++ api/serializers.py | 2 +- api/tasks.py | 6 ++++ api/views.py | 1 + tests/test_trade_pipeline.py | 54 ++++++++++++++++++++++++++++++++++++ tests/utils/trade.py | 7 +++++ 8 files changed, 119 insertions(+), 5 deletions(-) diff --git a/api/admin.py b/api/admin.py index 01d4f2d5..0ca8e536 100644 --- a/api/admin.py +++ b/api/admin.py @@ -210,6 +210,7 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin): f"Dispute of order {order.id} solved successfully on favor of the maker", messages.SUCCESS, ) + send_notification.delay(order_id=order.id, message="dispute_closed") else: self.message_user( @@ -248,6 +249,7 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin): f"Dispute of order {order.id} solved successfully on favor of the taker", messages.SUCCESS, ) + send_notification.delay(order_id=order.id, message="dispute_closed") else: self.message_user( diff --git a/api/models/order.py b/api/models/order.py index 161f6d3e..f9a72ecf 100644 --- a/api/models/order.py +++ b/api/models/order.py @@ -10,6 +10,7 @@ from django.db import models from django.db.models.signals import pre_delete from django.dispatch import receiver from django.utils import timezone +from api.tasks import send_notification if config("TESTING", cast=bool, default=False): import random @@ -91,10 +92,7 @@ class Order(models.Model): decimal_places=2, default=0, null=True, - validators=[ - MinValueValidator(Decimal(-100)), - MaxValueValidator(Decimal(999)) - ], + validators=[MinValueValidator(Decimal(-100)), MaxValueValidator(Decimal(999))], blank=True, ) # explicit @@ -352,6 +350,8 @@ class Order(models.Model): self.log( f"Order state went from {old_status}: {Order.Status(old_status).label} to {new_status}: {Order.Status(new_status).label}" ) + if new_status == Order.Status.FAI: + send_notification.delay(order_id=self.id, message="lightning_failed") @receiver(pre_delete, sender=Order) diff --git a/api/notifications.py b/api/notifications.py index 480c6d47..7adc9f60 100644 --- a/api/notifications.py +++ b/api/notifications.py @@ -219,3 +219,47 @@ class Notifications: title = f"๐Ÿ› ๏ธ Your order with ID {order.id} has been cancelled by the coordinator {config('COORDINATOR_ALIAS', cast=str, default='NoAlias')} for the upcoming maintenance stop." self.send_message(order, order.maker.robot, title) return + + def dispute_closed(self, order): + lang = order.maker.robot.telegram_lang_code + if order.status == Order.Status.MLD: + # Maker lost dispute + looser = order.maker + winner = order.taker + elif order.status == Order.Status.TLD: + # Taker lost dispute + looser = order.taker + winner = order.maker + + lang = looser.robot.telegram_lang_code + if lang == "es": + title = f"โš–๏ธ Hey {looser.username}, has perdido la disputa en la orden con ID {str(order.id)}." + else: + title = f"โš–๏ธ Hey {looser.username}, you lost the dispute on your order with ID {str(order.id)}." + self.send_message(order, looser.robot, title) + + lang = winner.robot.telegram_lang_code + if lang == "es": + title = f"โš–๏ธ Hey {winner.username}, has ganado la disputa en la orden con ID {str(order.id)}." + else: + title = f"โš–๏ธ Hey {winner.username}, you won the dispute on your order with ID {str(order.id)}." + self.send_message(order, winner.robot, title) + + return + + def lightning_failed(self, order): + lang = order.maker.robot.telegram_lang_code + if order.type == Order.Types.BUY: + buyer = order.maker + else: + buyer = order.taker + + if lang == "es": + title = f"โšกโŒ Hey {buyer.username}, el pago lightning en la order con ID {str(order.id)} ha fallado." + description = "Intentalo de nuevo con una nueva factura o con otra wallet." + else: + title = f"โšกโŒ Hey {buyer.username}, the lightning payment on your order with ID {str(order.id)} failed." + description = "Try again with a new invoice or from another wallet." + + self.send_message(order, buyer.robot, title, description) + return diff --git a/api/serializers.py b/api/serializers.py index 2f7b2310..fb8a0cdd 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -493,7 +493,7 @@ class OrderDetailSerializer(serializers.ModelSerializer): class ListNotificationSerializer(serializers.ModelSerializer): class Meta: model = Notification - fields = ("title", "description", "order_id") + fields = ("title", "description", "order_id", "order_status") class OrderPublicSerializer(serializers.ModelSerializer): diff --git a/api/tasks.py b/api/tasks.py index 88e924a8..656feb89 100644 --- a/api/tasks.py +++ b/api/tasks.py @@ -303,4 +303,10 @@ def send_notification(order_id=None, chat_message_id=None, message=None): elif message == "coordinator_cancelled": notifications.coordinator_cancelled(order) + elif message == "dispute_closed": + notifications.dispute_closed(order) + + elif message == "lightning_failed": + notifications.lightning_failed(order) + return diff --git a/api/views.py b/api/views.py index 0caa7407..171dfe24 100644 --- a/api/views.py +++ b/api/views.py @@ -764,6 +764,7 @@ class NotificationsView(ListAPIView): data["title"] = str(notification.title) data["description"] = str(notification.description) data["order_id"] = notification.order.id + data["order_status"] = notification.order.status notification_data.append(data) diff --git a/tests/test_trade_pipeline.py b/tests/test_trade_pipeline.py index bf438a48..91e6d75a 100644 --- a/tests/test_trade_pipeline.py +++ b/tests/test_trade_pipeline.py @@ -1163,6 +1163,60 @@ class TradeTest(BaseAPITestCase): f"โš–๏ธ Hey {data['taker_nick']}, a dispute has been opened on your order with ID {str(trade.order_id)}.", ) + # def test_dispute_closed_maker_wins(self): + # trade = Trade(self.client) + # trade.publish_order() + # trade.take_order() + # trade.lock_taker_bond() + # trade.lock_escrow(trade.taker_index) + # trade.submit_payout_invoice(trade.maker_index) + + # trade.change_order_status(Order.Status.TLD) + + # trade.clean_orders() + + # maker_headers = trade.get_robot_auth(trade.maker_index) + # response = self.client.get(reverse("notifications"), **maker_headers) + # self.assertResponse(response) + # notifications_data = list(response.json()) + # self.assertEqual(notifications_data[0]["order_id"], trade.order_id) + # self.assertEqual( + # notifications_data[0]["title"], + # f"โš–๏ธ Hey {data['maker_nick']}, you won the dispute on your order with ID {str(trade.order_id)}." + # ) + # taker_headers = trade.get_robot_auth(trade.taker_index) + # response = self.client.get(reverse("notifications"), **taker_headers) + # self.assertResponse(response) + # notifications_data = list(response.json()) + # self.assertEqual(notifications_data[0]["order_id"], trade.order_id) + # self.assertEqual( + # notifications_data[0]["title"], + # f"โš–๏ธ Hey {data['taker_nick']}, you lost the dispute on your order with ID {str(trade.order_id)}." + # ) + + def test_lightning_payment_failed(self): + trade = Trade(self.client) + trade.publish_order() + trade.take_order() + trade.lock_taker_bond() + trade.lock_escrow(trade.taker_index) + trade.submit_payout_invoice(trade.maker_index) + + trade.change_order_status(Order.Status.FAI) + + trade.clean_orders() + + maker_headers = trade.get_robot_auth(trade.maker_index) + maker_nick = read_file(f"tests/robots/{trade.maker_index}/nickname") + response = self.client.get(reverse("notifications"), **maker_headers) + self.assertResponse(response) + notifications_data = list(response.json()) + self.assertEqual(notifications_data[0]["order_id"], trade.order_id) + self.assertEqual( + notifications_data[0]["title"], + f"โšกโŒ Hey {maker_nick}, the lightning payment on your order with ID {str(trade.order_id)} failed.", + ) + def test_withdraw_reward_after_unilateral_cancel(self): """ Tests withdraw rewards as taker after maker cancels order unilaterally diff --git a/tests/utils/trade.py b/tests/utils/trade.py index c00b8757..eaf5f023 100644 --- a/tests/utils/trade.py +++ b/tests/utils/trade.py @@ -271,3 +271,10 @@ class Trade: order = Order.objects.get(id=self.order_id) order.expires_at = datetime.now() order.save() + + @patch("api.tasks.send_notification.delay", send_notification) + def change_order_status(self, status): + # Change order expiry to now + order = Order.objects.get(id=self.order_id) + order.status = status + order.save()