From 7d7a3a39e7e9ec9f5173f563b328a57213708875 Mon Sep 17 00:00:00 2001 From: KoalaSat Date: Tue, 1 Oct 2024 19:35:57 +0000 Subject: [PATCH] Revert "Store status notifications" --- api/admin.py | 6 ++ api/lightning/cln.py | 8 +- api/lightning/lnd.py | 7 +- api/logics.py | 74 ++++++++++-------- api/management/commands/follow_invoices.py | 6 +- api/management/commands/telegram_watcher.py | 7 +- api/models/order.py | 5 +- api/notifications.py | 17 ++--- api/tasks.py | 84 ++++++++++----------- chat/consumers.py | 5 +- chat/views.py | 6 +- docs/assets/schemas/api-latest.yaml | 2 +- tests/test_trade_pipeline.py | 54 ++----------- tests/utils/node.py | 3 +- tests/utils/trade.py | 36 ++++----- 15 files changed, 139 insertions(+), 181 deletions(-) diff --git a/api/admin.py b/api/admin.py index e9957a1d2..0ca8e536f 100644 --- a/api/admin.py +++ b/api/admin.py @@ -11,6 +11,7 @@ from api.logics import Logics from api.models import Currency, LNPayment, MarketTick, OnchainPayment, Order, Robot from api.utils import objects_to_hyperlinks +from api.tasks import send_notification admin.site.unregister(Group) admin.site.unregister(User) @@ -163,6 +164,9 @@ def cancel_public_order(self, request, queryset): f"Order {order.id} successfully closed", messages.SUCCESS, ) + send_notification.delay( + order_id=order.id, message="coordinator_cancelled" + ) else: self.message_user( request, @@ -206,6 +210,7 @@ def maker_wins(self, request, queryset): 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( @@ -244,6 +249,7 @@ def taker_wins(self, request, queryset): 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/lightning/cln.py b/api/lightning/cln.py index 0c0acba5e..824884178 100755 --- a/api/lightning/cln.py +++ b/api/lightning/cln.py @@ -617,10 +617,10 @@ def handle_response(): ] ) + order.update_status(Order.Status.FAI) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.FAI) ) - order.update_status(Order.Status.FAI) order.save(update_fields=["expires_at"]) print( @@ -646,10 +646,10 @@ def handle_response(): ) lnpayment.preimage = response.payment_preimage.hex() lnpayment.save(update_fields=["status", "fee", "preimage"]) + order.update_status(Order.Status.SUC) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.SUC) ) - order.update_status(Order.Status.SUC) order.save(update_fields=["expires_at"]) order.log( @@ -697,10 +697,10 @@ def handle_response(): ] ) + order.update_status(Order.Status.FAI) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.FAI) ) - order.update_status(Order.Status.FAI) order.save(update_fields=["expires_at"]) print( @@ -737,10 +737,10 @@ def handle_response(): "in_flight", ] ) + order.update_status(Order.Status.FAI) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.FAI) ) - order.update_status(Order.Status.FAI) order.save(update_fields=["expires_at"]) order.log( diff --git a/api/lightning/lnd.py b/api/lightning/lnd.py index 96562a681..f914857e8 100644 --- a/api/lightning/lnd.py +++ b/api/lightning/lnd.py @@ -594,10 +594,11 @@ def handle_response(response, was_in_transit=False): ] ) + order.update_status(Order.Status.FAI) + order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.FAI) ) - order.update_status(Order.Status.FAI) order.save(update_fields=["expires_at"]) str_failure_reason = cls.payment_failure_context[ @@ -624,10 +625,10 @@ def handle_response(response, was_in_transit=False): lnpayment.preimage = response.payment_preimage lnpayment.save(update_fields=["status", "fee", "preimage"]) + order.update_status(Order.Status.SUC) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.SUC) ) - order.update_status(Order.Status.SUC) order.save(update_fields=["expires_at"]) order.log( @@ -670,10 +671,10 @@ def handle_response(response, was_in_transit=False): update_fields=["status", "last_routing_time", "in_flight"] ) + order.update_status(Order.Status.FAI) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.FAI) ) - order.update_status(Order.Status.FAI) order.save(update_fields=["expires_at"]) order.log( diff --git a/api/logics.py b/api/logics.py index c5055fbde..8bec242aa 100644 --- a/api/logics.py +++ b/api/logics.py @@ -8,11 +8,7 @@ from api.lightning.node import LNNode from api.models import Currency, LNPayment, MarketTick, OnchainPayment, Order -from api.tasks import ( - send_devfund_donation, - send_status_notification, - nostr_send_order_event, -) +from api.tasks import send_devfund_donation, send_notification, nostr_send_order_event from api.utils import get_minning_fee, validate_onchain_address, location_country from chat.models import Message @@ -184,10 +180,10 @@ def take(cls, order, user, amount=None): if order.has_range: order.amount = amount order.taker = user + order.update_status(Order.Status.TAK) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.TAK) ) - order.update_status(Order.Status.TAK) order.save(update_fields=["amount", "taker", "expires_at"]) order.log( f"Taken by Robot({user.robot.id},{user.username}) for {order.amount} fiat units" @@ -271,9 +267,9 @@ def order_expires(cls, order): return False elif order.status == Order.Status.WFB: + order.update_status(Order.Status.EXP) order.expiry_reason = Order.ExpiryReasons.NMBOND cls.cancel_bond(order.maker_bond) - order.update_status(Order.Status.EXP) order.save(update_fields=["expiry_reason"]) order.log("Order expired while waiting for maker bond") @@ -283,9 +279,10 @@ def order_expires(cls, order): elif order.status in [Order.Status.PUB, Order.Status.PAU]: cls.return_bond(order.maker_bond) + order.update_status(Order.Status.EXP) order.expiry_reason = Order.ExpiryReasons.NTAKEN order.save(update_fields=["expiry_reason"]) - order.update_status(Order.Status.EXP) + send_notification.delay(order_id=order.id, message="order_expired_untaken") order.log("Order expired while public or paused") order.log("Maker bond was unlocked") @@ -310,8 +307,8 @@ def order_expires(cls, order): cls.settle_bond(order.maker_bond) cls.settle_bond(order.taker_bond) cls.cancel_escrow(order) - order.expiry_reason = Order.ExpiryReasons.NESINV order.update_status(Order.Status.EXP) + order.expiry_reason = Order.ExpiryReasons.NESINV order.save(update_fields=["expiry_reason"]) order.log( @@ -333,8 +330,8 @@ def order_expires(cls, order): cls.cancel_escrow(order) except Exception: pass - order.expiry_reason = Order.ExpiryReasons.NESCRO order.update_status(Order.Status.EXP) + order.expiry_reason = Order.ExpiryReasons.NESCRO order.save(update_fields=["expiry_reason"]) # Reward taker with part of the maker bond cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond) @@ -355,9 +352,7 @@ def order_expires(cls, order): pass taker_bond = order.taker_bond cls.publish_order(order) - send_status_notification.delay( - order_id=order.id, status=Order.Status.PUB - ) + send_notification.delay(order_id=order.id, message="order_published") # Reward maker with part of the taker bond cls.add_slashed_rewards(order, taker_bond, order.maker_bond) @@ -376,8 +371,8 @@ def order_expires(cls, order): cls.settle_bond(order.maker_bond) cls.return_bond(order.taker_bond) cls.return_escrow(order) - order.expiry_reason = Order.ExpiryReasons.NINVOI order.update_status(Order.Status.EXP) + order.expiry_reason = Order.ExpiryReasons.NINVOI order.save(update_fields=["expiry_reason"]) # Reward taker with part of the maker bond cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond) @@ -394,9 +389,7 @@ def order_expires(cls, order): cls.return_escrow(order) taker_bond = order.taker_bond cls.publish_order(order) - send_status_notification.delay( - order_id=order.id, status=Order.Status.PUB - ) + send_notification.delay(order_id=order.id, message="order_published") # Reward maker with part of the taker bond cls.add_slashed_rewards(order, taker_bond, order.maker_bond) @@ -505,6 +498,7 @@ def automatic_dispute_resolution(cls, order): seconds=order.t_to_expire(Order.Status.DIS) ) order.save(update_fields=["is_disputed", "expires_at"]) + send_notification.delay(order_id=order.id, message="dispute_opened") return True @@ -536,10 +530,10 @@ def open_dispute(cls, order, user=None): cls.settle_bond(order.taker_bond) order.is_disputed = True + order.update_status(Order.Status.DIS) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.DIS) ) - order.update_status(Order.Status.DIS) order.save(update_fields=["is_disputed", "expires_at"]) # User could be None if a dispute is open automatically due to time expiration. @@ -554,6 +548,7 @@ def open_dispute(cls, order, user=None): ).append(str(order.id)) robot.save(update_fields=["num_disputes", "orders_disputes_started"]) + send_notification.delay(order_id=order.id, message="dispute_opened") order.log( f"Dispute was opened {f'by Robot({user.robot.id},{user.username})' if user else ''}" ) @@ -592,10 +587,10 @@ def dispute_statement(order, user, statement): None, "", ]: + order.update_status(Order.Status.WFR) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.WFR) ) - order.update_status(Order.Status.WFR) order.save(update_fields=["status", "expires_at"]) order.log( @@ -949,10 +944,11 @@ def update_invoice(cls, order, user, invoice, routing_budget_ppm): def move_state_updated_payout_method(cls, order): # If the order status is 'Waiting for invoice'. Move forward to 'chat' if order.status == Order.Status.WFI: + order.update_status(Order.Status.CHA) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.CHA) ) - order.update_status(Order.Status.CHA) + send_notification.delay(order_id=order.id, message="fiat_exchange_starts") # If the order status is 'Waiting for both'. Move forward to 'waiting for escrow' elif order.status == Order.Status.WF2: @@ -962,19 +958,22 @@ def move_state_updated_payout_method(cls, order): # If the escrow is locked move to Chat. elif order.trade_escrow.status == LNPayment.Status.LOCKED: + order.update_status(Order.Status.CHA) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.CHA) ) - order.update_status(Order.Status.CHA) + send_notification.delay( + order_id=order.id, message="fiat_exchange_starts" + ) else: order.update_status(Order.Status.WFE) # If the order status is 'Failed Routing'. Retry payment. elif order.status == Order.Status.FAI: if LNNode.double_check_htlc_is_settled(order.trade_escrow.payment_hash): + order.update_status(Order.Status.PAY) order.payout.status = LNPayment.Status.FLIGHT order.payout.routing_attempts = 0 - order.update_status(Order.Status.PAY) order.payout.save(update_fields=["status", "routing_attempts"]) order.save(update_fields=["expires_at"]) @@ -1035,6 +1034,10 @@ def cancel_order(cls, order, user, state=None): # Return the maker bond (Maker gets returned the bond for cancelling public order) if cls.return_bond(order.maker_bond): order.update_status(Order.Status.UCA) + send_notification.delay( + order_id=order.id, message="public_order_cancelled" + ) + order.log("Order cancelled by maker while public or paused") order.log("Maker bond was unlocked") @@ -1051,6 +1054,9 @@ def cancel_order(cls, order, user, state=None): if cls.return_bond(order.maker_bond): cls.cancel_bond(order.taker_bond) order.update_status(Order.Status.UCA) + send_notification.delay( + order_id=order.id, message="public_order_cancelled" + ) order.log("Order cancelled by maker before the taker locked the bond") order.log("Maker bond was unlocked") @@ -1117,9 +1123,7 @@ def cancel_order(cls, order, user, state=None): if valid: taker_bond = order.taker_bond cls.publish_order(order) - send_status_notification.delay( - order_id=order.id, status=Order.Status.PUB - ) + send_notification.delay(order_id=order.id, message="order_published") # Reward maker with part of the taker bond cls.add_slashed_rewards(order, taker_bond, order.maker_bond) @@ -1193,6 +1197,7 @@ def collaborative_cancel(cls, order): cls.return_bond(order.taker_bond) cls.return_escrow(order) order.update_status(Order.Status.CCA) + send_notification.delay(order_id=order.id, message="collaborative_cancelled") nostr_send_order_event.delay(order_id=order.id) @@ -1205,6 +1210,7 @@ def collaborative_cancel(cls, order): @classmethod def publish_order(cls, order): + order.status = Order.Status.PUB order.expires_at = order.created_at + timedelta( seconds=order.t_to_expire(Order.Status.PUB) ) @@ -1220,7 +1226,6 @@ def publish_order(cls, order): order.payout = None order.payout_tx = None - order.update_status(Order.Status.PUB) order.save() # update all fields nostr_send_order_event.delay(order_id=order.id) @@ -1339,6 +1344,7 @@ def finalize_contract(cls, order): order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.WF2) ) + order.status = Order.Status.WF2 order.save( update_fields=[ "status", @@ -1365,8 +1371,7 @@ def finalize_contract(cls, order): ) except Exception: pass - - order.update_status(Order.Status.WF2) + send_notification.delay(order_id=order.id, message="order_taken_confirmed") nostr_send_order_event.delay(order_id=order.id) @@ -1466,11 +1471,12 @@ def trade_escrow_received(order): order.update_status(Order.Status.WFI) # If status is 'Waiting for invoice' move to Chat elif order.status == Order.Status.WFE: + order.update_status(Order.Status.CHA) order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.CHA) ) - order.update_status(Order.Status.CHA) order.save(update_fields=["expires_at"]) + send_notification.delay(order_id=order.id, message="fiat_exchange_starts") @classmethod def gen_escrow_hold_invoice(cls, order, user): @@ -1638,10 +1644,11 @@ def pay_buyer(cls, order): order.payout.status = LNPayment.Status.FLIGHT order.payout.save(update_fields=["status"]) - order.contract_finalization_time = timezone.now() order.update_status(Order.Status.PAY) + order.contract_finalization_time = timezone.now() order.save(update_fields=["contract_finalization_time"]) + send_notification.delay(order_id=order.id, message="trade_successful") order.log("Paying buyer invoice") return True @@ -1654,10 +1661,11 @@ def pay_buyer(cls, order): order.payout_tx.status = OnchainPayment.Status.QUEUE order.payout_tx.save(update_fields=["status"]) - order.contract_finalization_time = timezone.now() order.update_status(Order.Status.SUC) + order.contract_finalization_time = timezone.now() order.save(update_fields=["contract_finalization_time"]) + send_notification.delay(order_id=order.id, message="trade_successful") order.log("Paying buyer onchain address") return True @@ -1671,8 +1679,8 @@ def confirm_fiat(cls, order, user): if order.status == Order.Status.CHA or order.status == Order.Status.FSE: # If buyer mark fiat sent if cls.is_buyer(order, user): - order.is_fiat_sent = True order.update_status(Order.Status.FSE) + order.is_fiat_sent = True order.save(update_fields=["is_fiat_sent"]) order.log("Buyer confirmed 'fiat sent'") @@ -1736,9 +1744,9 @@ def undo_confirm_fiat_sent(cls, order, user): return False, { "bad_request": "Only orders in Chat and with fiat sent confirmed can be reverted." } + order.update_status(Order.Status.CHA) order.is_fiat_sent = False order.reverted_fiat_sent = True - order.update_status(Order.Status.CHA) order.save(update_fields=["is_fiat_sent", "reverted_fiat_sent"]) order.log( diff --git a/api/management/commands/follow_invoices.py b/api/management/commands/follow_invoices.py index 93b1f34c8..8b4b98c18 100644 --- a/api/management/commands/follow_invoices.py +++ b/api/management/commands/follow_invoices.py @@ -8,7 +8,7 @@ from api.lightning.node import LNNode from api.logics import Logics from api.models import LNPayment, OnchainPayment, Order -from api.tasks import follow_send_payment, send_status_notification +from api.tasks import follow_send_payment, send_notification def is_same_status(a: LNPayment.Status, b: LNPayment.Status) -> bool: @@ -229,8 +229,8 @@ def update_order_status(self, lnpayment): if hasattr(lnpayment, "order_made"): lnpayment.order_made.log("Maker bond locked") Logics.publish_order(lnpayment.order_made) - send_status_notification.delay( - order_id=lnpayment.order_made.id, status=Order.Status.PUB + send_notification.delay( + order_id=lnpayment.order_made.id, message="order_published" ) return diff --git a/api/management/commands/telegram_watcher.py b/api/management/commands/telegram_watcher.py index 5f57dcaef..d626b7569 100644 --- a/api/management/commands/telegram_watcher.py +++ b/api/management/commands/telegram_watcher.py @@ -6,8 +6,8 @@ from django.db import transaction from api.models import Robot +from api.notifications import Notifications from api.utils import get_session -from api.tasks import send_telegram_notification class Command(BaseCommand): @@ -17,6 +17,7 @@ class Command(BaseCommand): bot_token = config("TELEGRAM_TOKEN") updates_url = f"https://api.telegram.org/bot{bot_token}/getUpdates" session = get_session() + notifications = Notifications() def handle(self, *args, **options): offset = 0 @@ -48,7 +49,7 @@ def handle(self, *args, **options): continue parts = message.split(" ") if len(parts) < 2: - send_telegram_notification.delay( + self.notifications.send_telegram_message( result["message"]["from"]["id"], 'You must enable the notifications bot using the RoboSats client. Click on your "Robot robot" -> "Enable Telegram" and follow the link or scan the QR code.', ) @@ -56,7 +57,7 @@ def handle(self, *args, **options): token = parts[-1] robot = Robot.objects.filter(telegram_token=token).first() if not robot: - send_telegram_notification.delay( + self.notifications.send_telegram_message( result["message"]["from"]["id"], f'Wops, invalid token! There is no Robot with telegram chat token "{token}"', ) diff --git a/api/models/order.py b/api/models/order.py index abd34a2e3..483e6fa44 100644 --- a/api/models/order.py +++ b/api/models/order.py @@ -10,7 +10,7 @@ from django.db.models.signals import pre_delete from django.dispatch import receiver from django.utils import timezone -from api.tasks import send_status_notification +from api.tasks import send_notification if config("TESTING", cast=bool, default=False): import random @@ -350,7 +350,8 @@ def update_status(self, new_status): self.log( f"Order state went from {old_status}: {Order.Status(old_status).label} to {new_status}: {Order.Status(new_status).label}" ) - send_status_notification.delay(order_id=self.id, status=self.status) + 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 7792d6a00..57ec4a429 100644 --- a/api/notifications.py +++ b/api/notifications.py @@ -57,18 +57,6 @@ def send_telegram_message(self, chat_id, title, description=""): except Exception: pass - def status_change(self, order): - Notification.objects.create( - title="", description="", robot=order.maker.robot, order=order - ) - - if order.taker: - Notification.objects.create( - title="", description="", robot=order.taker.robot, order=order - ) - - return - def welcome(self, user): """User enabled Telegram Notifications""" lang = user.robot.telegram_lang_code @@ -227,6 +215,11 @@ def new_chat_message(self, order, chat_message): return + def coordinator_cancelled(self, order): + 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: diff --git a/api/tasks.py b/api/tasks.py index fffe0acff..416a58475 100644 --- a/api/tasks.py +++ b/api/tasks.py @@ -251,6 +251,7 @@ def cache_market(): print("SOFT LIMIT REACHED. Could not fetch current external market prices.") return + @shared_task(name="", ignore_result=True, time_limit=120) def nostr_send_order_event(order_id=None): if order_id: @@ -264,70 +265,63 @@ def nostr_send_order_event(order_id=None): return -@shared_task(name="send_chat_notification", ignore_result=True, time_limit=120) -def send_chat_notification(message_id=None, order_id=None): - if message_id and order_id: + +@shared_task(name="send_notification", ignore_result=True, time_limit=120) +def send_notification(order_id=None, chat_message_id=None, message=None): + if order_id: from api.models import Order - from chat.models import Message - from api.notifications import Notifications order = Order.objects.get(id=order_id) - chat_message = Message.objects.get(id=message_id) - notifications = Notifications() - - notifications.new_chat_message(order, chat_message) - + elif chat_message_id: + from chat.models import Message -@shared_task(name="send_telegram_notification", ignore_result=True, time_limit=120) -def send_telegram_notification(chat_id=None, message=None): - if chat_id: - from api.notifications import Notifications + chat_message = Message.objects.get(id=chat_message_id) + order = chat_message.order - notifications = Notifications() + from api.notifications import Notifications - notifications.send_telegram_message(chat_id, message) + notifications = Notifications() + if message == "welcome": + notifications.welcome(order) -@shared_task(name="send_status_notification", ignore_result=True, time_limit=120) -def send_status_notification(order_id=None, status=None): - if order_id: - from api.models import Order - from api.notifications import Notifications + elif message == "order_expired_untaken": + notifications.order_expired_untaken(order) - order = Order.objects.get(id=order_id) - notifications = Notifications() + elif message == "trade_successful": + notifications.trade_successful(order) - if status == Order.Status.EXP: - notifications.order_expired_untaken(order) + elif message == "public_order_cancelled": + notifications.public_order_cancelled(order) - elif status == Order.Status.PAY or status == Order.Status.SUC: - notifications.trade_successful(order) + elif message == "taker_expired_b4bond": + notifications.taker_expired_b4bond(order) - elif status == Order.Status.UCA: - notifications.public_order_cancelled(order) + elif message == "order_published": + notifications.order_published(order) - elif status == Order.Status.PUB: - notifications.order_published(order) + elif message == "order_taken_confirmed": + notifications.order_taken_confirmed(order) - elif status == Order.Status.WF2: - notifications.order_taken_confirmed(order) + elif message == "fiat_exchange_starts": + notifications.fiat_exchange_starts(order) - elif status == Order.Status.CHA: - notifications.fiat_exchange_starts(order) + elif message == "dispute_opened": + notifications.dispute_opened(order) - elif status == Order.Status.DIS: - notifications.dispute_opened(order) + elif message == "collaborative_cancelled": + notifications.collaborative_cancelled(order) - elif status == Order.Status.CCA: - notifications.collaborative_cancelled(order) + elif message == "new_chat_message": + notifications.new_chat_message(order, chat_message) - elif status == Order.Status.TLD or status == Order.Status.MLD: - notifications.dispute_closed(order) + elif message == "coordinator_cancelled": + notifications.coordinator_cancelled(order) - elif status == Order.Status.FAI: - notifications.lightning_failed(order) + elif message == "dispute_closed": + notifications.dispute_closed(order) - else: - notifications.status_change(order) + elif message == "lightning_failed": + notifications.lightning_failed(order) return diff --git a/chat/consumers.py b/chat/consumers.py index 1c32ac872..c2443e665 100644 --- a/chat/consumers.py +++ b/chat/consumers.py @@ -4,7 +4,7 @@ from channels.generic.websocket import AsyncWebsocketConsumer from api.models import Order -from api.tasks import send_chat_notification +from api.tasks import send_notification from chat.models import ChatRoom, Message @@ -85,8 +85,7 @@ def save_new_PGP_message(self, PGP_message): ) # send Telegram notification for new message (if conditions apply) - send_chat_notification.delay(message_id=msg_obj.id, order_id=order.id) - + send_notification.delay(chat_message_id=msg_obj.id, message="new_chat_message") return msg_obj @database_sync_to_async diff --git a/chat/views.py b/chat/views.py index fc15f73dd..ab2881698 100644 --- a/chat/views.py +++ b/chat/views.py @@ -11,7 +11,7 @@ from rest_framework.response import Response from api.models import Order -from api.tasks import send_chat_notification +from api.tasks import send_notification from chat.models import ChatRoom, Message from chat.serializers import ChatSerializer, InMessageSerializer, PostMessageSerializer @@ -179,7 +179,9 @@ def post(self, request, format=None): ) # send Telegram notification for new message (if conditions apply) - send_chat_notification.delay(message_id=new_message.id, order_id=order.id) + send_notification.delay( + chat_message_id=new_message.id, message="new_chat_message" + ) # Send websocket message if chatroom.maker == request.user: diff --git a/docs/assets/schemas/api-latest.yaml b/docs/assets/schemas/api-latest.yaml index 2c8e044b7..04a0577fa 100644 --- a/docs/assets/schemas/api-latest.yaml +++ b/docs/assets/schemas/api-latest.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: RoboSats REST API - version: 0.7.0 + version: 0.6.3 x-logo: url: https://raw.githubusercontent.com/Reckless-Satoshi/robosats/main/frontend/static/assets/images/robosats-0.1.1-banner.png backgroundColor: '#FFFFFF' diff --git a/tests/test_trade_pipeline.py b/tests/test_trade_pipeline.py index 35ff1fd23..c226b5c01 100644 --- a/tests/test_trade_pipeline.py +++ b/tests/test_trade_pipeline.py @@ -560,21 +560,6 @@ def test_trade_to_submitted_invoice(self): trade.publish_order() trade.take_order() trade.lock_taker_bond() - - maker_nick = read_file(f"tests/robots/{trade.maker_index}/nickname") - taker_nick = read_file(f"tests/robots/{trade.taker_index}/nickname") - - 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) - # Does not receive notification because user is online - self.assertEqual( - notifications_data[0]["title"], - f"✅ Hey {maker_nick}, your order was taken by {taker_nick}!🥳", - ) - trade.lock_escrow(trade.taker_index) trade.submit_payout_invoice(trade.maker_index) @@ -586,6 +571,7 @@ def test_trade_to_submitted_invoice(self): self.assertEqual(data["status_message"], Order.Status(Order.Status.CHA).label) self.assertFalse(data["is_fiat_sent"]) + 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) @@ -859,16 +845,6 @@ def test_created_order_expires(self): self.assert_order_logs(data["id"]) - 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']}, your order with ID {str(trade.order_id)} has expired without a taker.", - ) - def test_public_order_expires(self): """ Tests the expiration of a public order @@ -941,16 +917,6 @@ def test_taken_order_expires(self): self.assert_order_logs(data["id"]) - 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']}, your order with ID {str(trade.order_id)} has expired without a taker.", - ) - def test_escrow_locked_expires(self): """ Tests the expiration of a public order @@ -987,16 +953,6 @@ def test_escrow_locked_expires(self): self.assert_order_logs(data["id"]) - 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']}, your order with ID {str(trade.order_id)} has expired without a taker.", - ) - def test_chat(self): """ Tests the chatting REST functionality @@ -1134,7 +1090,7 @@ def test_order_expires_after_only_taker_messaged(self): self.assertEqual(notifications_data[0]["order_id"], trade.order_id) self.assertEqual( notifications_data[0]["title"], - f"⚖️ Hey {data['maker_nick']}, you lost the dispute on your order with ID {str(trade.order_id)}.", + f"⚖️ Hey {data['maker_nick']}, a dispute has been opened 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) @@ -1143,7 +1099,7 @@ def test_order_expires_after_only_taker_messaged(self): self.assertEqual(notifications_data[0]["order_id"], trade.order_id) self.assertEqual( notifications_data[0]["title"], - f"⚖️ Hey {data['taker_nick']}, you won the dispute on your order with ID {str(trade.order_id)}.", + f"⚖️ Hey {data['taker_nick']}, a dispute has been opened on your order with ID {str(trade.order_id)}.", ) def test_order_expires_after_only_maker_messaged(self): @@ -1195,7 +1151,7 @@ def test_order_expires_after_only_maker_messaged(self): 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)}.", + f"⚖️ Hey {data['maker_nick']}, a dispute has been opened 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) @@ -1204,7 +1160,7 @@ def test_order_expires_after_only_maker_messaged(self): 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)}.", + 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): diff --git a/tests/utils/node.py b/tests/utils/node.py index 002de9bcc..d5cb1289e 100644 --- a/tests/utils/node.py +++ b/tests/utils/node.py @@ -269,7 +269,7 @@ def pay_invoice(node_name, invoice): node = get_node(node_name) data = {"payment_request": invoice} try: - requests.post( + response = requests.post( f'http://localhost:{node["port"]}/v1/channels/transactions', json=data, headers=node["headers"], @@ -277,6 +277,7 @@ def pay_invoice(node_name, invoice): # 0.4s is enough for LND to CLN hodl ACCEPT timeout=0.2 if LNVENDOR == "LND" else 1, ) + print(response.json()) except ReadTimeout: # Request to pay hodl invoice has timed out: that's good! return diff --git a/tests/utils/trade.py b/tests/utils/trade.py index f0258d674..39bcda0a1 100644 --- a/tests/utils/trade.py +++ b/tests/utils/trade.py @@ -5,11 +5,7 @@ from api.management.commands.clean_orders import Command as CleanOrders from api.management.commands.follow_invoices import Command as FollowInvoices from api.models import Order -from api.tasks import ( - follow_send_payment, - send_status_notification, - send_chat_notification, -) +from api.tasks import follow_send_payment, send_notification from tests.utils.node import ( add_invoice, create_address, @@ -115,7 +111,7 @@ def get_order(self, robot_index=1, first_encounter=False): headers = self.get_robot_auth(robot_index, first_encounter) self.response = self.client.get(path + params, **headers) - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def cancel_order(self, robot_index=1): path = reverse("order") params = f"?order_id={self.order_id}" @@ -123,14 +119,14 @@ def cancel_order(self, robot_index=1): body = {"action": "cancel"} self.response = self.client.post(path + params, body, **headers) - @patch("api.tasks.send_chat_notification.delay", send_chat_notification) + @patch("api.tasks.send_notification.delay", send_notification) def send_chat_message(self, message, robot_index=1): path = reverse("chat") headers = self.get_robot_auth(robot_index) body = {"PGP_message": message, "order_id": self.order_id, "offset": 0} self.response = self.client.post(path, data=body, **headers) - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def pause_order(self, robot_index=1): path = reverse("order") params = f"?order_id={self.order_id}" @@ -138,13 +134,13 @@ def pause_order(self, robot_index=1): body = {"action": "pause"} self.response = self.client.post(path + params, body, **headers) - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def follow_hold_invoices(self): # A background thread checks every 5 second the status of invoices. We invoke directly during test. follower = FollowInvoices() follower.follow_hold_invoices() - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def clean_orders(self): # A background thread checks every 5 second order expirations. We invoke directly during test. cleaner = CleanOrders() @@ -159,7 +155,7 @@ def process_payouts(self, mine_a_block=False): generate_blocks(create_address("robot"), 1) wait_nodes_sync() - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def publish_order(self): # Maker's first order fetch. Should trigger maker bond hold invoice generation. self.get_order() @@ -174,7 +170,7 @@ def publish_order(self): # Get order self.get_order() - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def take_order(self): path = reverse("order") params = f"?order_id={self.order_id}" @@ -182,7 +178,7 @@ def take_order(self): body = {"action": "take", "amount": self.take_amount} self.response = self.client.post(path + params, body, **headers) - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def lock_taker_bond(self): # Takers's first order fetch. Should trigger maker bond hold invoice generation. self.get_order(self.taker_index) @@ -197,7 +193,7 @@ def lock_taker_bond(self): # Get order self.get_order(self.taker_index) - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def lock_escrow(self, robot_index): # Takers's order fetch. Should trigger trade escrow bond hold invoice generation. self.get_order(robot_index) @@ -212,7 +208,7 @@ def lock_escrow(self, robot_index): # Get order self.get_order() - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def submit_payout_address(self, robot_index=1): path = reverse("order") params = f"?order_id={self.order_id}" @@ -231,7 +227,7 @@ def submit_payout_address(self, robot_index=1): } self.response = self.client.post(path + params, body, **headers) - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def submit_payout_invoice(self, robot_index=1, routing_budget=0): path = reverse("order") params = f"?order_id={self.order_id}" @@ -253,7 +249,7 @@ def submit_payout_invoice(self, robot_index=1, routing_budget=0): self.response = self.client.post(path + params, body, **headers) - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def confirm_fiat(self, robot_index=1): path = reverse("order") params = f"?order_id={self.order_id}" @@ -261,7 +257,7 @@ def confirm_fiat(self, robot_index=1): body = {"action": "confirm"} self.response = self.client.post(path + params, body, **headers) - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def undo_confirm_sent(self, robot_index=1): path = reverse("order") params = f"?order_id={self.order_id}" @@ -269,14 +265,14 @@ def undo_confirm_sent(self, robot_index=1): body = {"action": "undo_confirm"} self.response = self.client.post(path + params, body, **headers) - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @patch("api.tasks.send_notification.delay", send_notification) def expire_order(self): # Change order expiry to now order = Order.objects.get(id=self.order_id) order.expires_at = datetime.now() order.save() - @patch("api.tasks.send_status_notification.delay", send_status_notification) + @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)