diff --git a/api/logics.py b/api/logics.py index 39acce5b..3131bbcd 100644 --- a/api/logics.py +++ b/api/logics.py @@ -221,7 +221,6 @@ class Logics: order.expires_at = timezone.now() + timedelta( seconds=order.t_to_expire(Order.Status.TAK)) order.save() - # send_message.delay(order.id,'order_taken') # Too spammy return True, None def is_buyer(order, user): @@ -315,7 +314,6 @@ class Logics: elif order.status == Order.Status.TAK: cls.cancel_bond(order.taker_bond) cls.kick_taker(order) - # send_message.delay(order.id,'taker_expired_b4bond') # Too spammy return True elif order.status == Order.Status.WF2: @@ -882,7 +880,6 @@ class Logics: # adds a timeout penalty cls.cancel_bond(order.taker_bond) cls.kick_taker(order) - # send_message.delay(order.id,'taker_canceled_b4bond') # too spammy return True, None # 4) When taker or maker cancel after bond (before escrow) diff --git a/api/messages.py b/api/messages.py index b22c7c81..0021729a 100644 --- a/api/messages.py +++ b/api/messages.py @@ -8,6 +8,7 @@ class Telegram(): ''' Simple telegram messages by requesting to API''' session = get_session() + site = config('HOST_NAME') def get_context(user): """returns context needed to enable TG notifications""" @@ -41,188 +42,131 @@ class Telegram(): return except: pass - + def welcome(self, user): + ''' User enabled Telegram Notifications''' lang = user.profile.telegram_lang_code - # In weird cases the order cannot be found (e.g. it is cancelled) - queryset = Order.objects.filter(maker=user) - order = queryset.last() - - print(str(order.id)) if lang == 'es': - text = f'Hola {user.username}, te enviaré un mensaje cuando tu orden con ID {str(order.id)} haya sido tomada.' + text = f'Hola {user.username}, te enviaré notificaciones sobre tus órdenes en RoboSats.' else: - text = f"Hey {user.username}, I will send you a message when someone takes your order with ID {str(order.id)}." + text = f"Hey {user.username}, I will send you notifications about your RoboSats orders." self.send_message(user, text) user.profile.telegram_welcomed = True user.profile.save() return - def order_taken(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return + # def welcome(self, user): + # lang = user.profile.telegram_lang_code + + # # In weird cases the order cannot be found (e.g. it is cancelled) + # queryset = Order.objects.filter(maker=user) + # order = queryset.last() + + # print(str(order.id)) + # if lang == 'es': + # text = f'Hola {user.username}, te enviaré un mensaje cuando tu orden con ID {str(order.id)} haya sido tomada.' + # else: + # text = f"Hey {user.username}, I will send you a message when someone takes your order with ID {str(order.id)}." + # self.send_message(user, text) + # user.profile.telegram_welcomed = True + # user.profile.save() + # return - lang = user.profile.telegram_lang_code - taker_nick = order.taker.username - site = config('HOST_NAME') - if lang == 'es': - text = f'Hey {order.maker.username} ¡Tu orden con ID {order.id} ha sido tomada por {taker_nick}!🥳 Visita http://{site}/order/{order.id} para continuar.' - else: - text = f'Hey {order.maker.username}, your order was taken by {taker_nick}!🥳 Visit http://{site}/order/{order.id} to proceed with the trade.' - - self.send_message(user, text) - return - def order_taken_confirmed(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return + if order.maker.profile.telegram_enabled: + lang = order.maker.profile.telegram_lang_code + if lang == 'es': + text = f'Hey {order.maker.username} ¡Tu orden con ID {order.id} ha sido tomada por {order.taker.username}!🥳 Visita http://{self.site}/order/{order.id} para continuar.' + else: + text = f'Hey {order.maker.username}, your order was taken by {order.taker.username}!🥳 Visit http://{self.site}/order/{order.id} to proceed with the trade.' + self.send_message(order.maker, text) + + if order.taker.profile.telegram_enabled: + lang = order.taker.profile.telegram_lang_code + if lang == 'es': + text = f'Hey {order.taker.username}, acabas de tomar la orden con ID {order.id}.' + else: + text = f'Hey {order.taker.username}, you just took the order with ID {order.id}.' + self.send_message(order.taker, text) - lang = user.profile.telegram_lang_code - taker_nick = order.taker.username - site = config('HOST_NAME') - if lang == 'es': - text = f'Hey {order.maker.username} ¡Tu orden con ID {order.id} ha sido tomada por {taker_nick}!🥳 El tomador ya ha bloqueado su fianza. Visita http://{site}/order/{order.id} para continuar.' - else: - text = f'Hey {order.maker.username}, your order with ID {order.id} was taken by {taker_nick}!🥳 The taker bond has already been locked. Visit http://{site}/order/{order.id} to proceed with the trade.' - - self.send_message(user, text) return def fiat_exchange_starts(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return - - lang = user.profile.telegram_lang_code - site = config('HOST_NAME') - if lang == 'es': - text = f'Hey {order.maker.username}, el depósito de garantía y el recibo del comprador han sido recibidos. Es hora de enviar el dinero fiat. Visita http://{site}/order/{order.id} para hablar con tu contraparte.' - else: - text = f'Hey {order.maker.username}, the escrow and invoice have been submitted. The fiat exchange starts now via the platform chat. Visit http://{site}/order/{order.id} to talk with your counterpart.' - - self.send_message(user, text) + for user in [order.maker, order.taker]: + if user.profile.telegram_enabled: + lang = user.profile.telegram_lang_code + if lang == 'es': + text = f'Hey {user.username}, el depósito de garantía y el recibo del comprador han sido recibidos. Es hora de enviar el dinero fiat. Visita http://{self.site}/order/{order.id} para hablar con tu contraparte.' + else: + text = f'Hey {user.username}, the escrow and invoice have been submitted. The fiat exchange starts now via the platform chat. Visit http://{self.site}/order/{order.id} to talk with your counterpart.' + self.send_message(user, text) return def order_expired_untaken(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return - - lang = user.profile.telegram_lang_code - site = config('HOST_NAME') - if lang == 'es': - text = f'Hey {order.maker.username}, tu orden con ID {order.id} ha expirado sin ser tomada por ningún robot. Visita http://{site}/order/{order.id} para renovarla.' - else: - text = f'Hey {order.maker.username}, your order with ID {order.id} has expired without a taker. Visit http://{site}/order/{order.id} to renew it.' - - self.send_message(user, text) + if order.maker.profile.telegram_enabled: + lang = order.maker.profile.telegram_lang_code + if lang == 'es': + text = f'Hey {order.maker.username}, tu orden con ID {order.id} ha expirado sin ser tomada por ningún robot. Visita http://{self.site}/order/{order.id} para renovarla.' + else: + text = f'Hey {order.maker.username}, your order with ID {order.id} has expired without a taker. Visit http://{self.site}/order/{order.id} to renew it.' + self.send_message(order.maker, text) return def trade_successful(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return - - lang = user.profile.telegram_lang_code - if lang == 'es': - text = f'¡Tu orden con ID {order.id} ha finalizado exitosamente!⚡ Únete a nosotros en @robosats_es y ayúdanos a mejorar.' - else: - text = f'Your order with ID {order.id} has finished successfully!⚡ Join us @robosats and help us improve.' - - self.send_message(user, text) + for user in [order.maker, order.taker]: + if user.profile.telegram_enabled: + lang = user.profile.telegram_lang_code + if lang == 'es': + text = f'¡Tu orden con ID {order.id} ha finalizado exitosamente!⚡ Únete a nosotros en @robosats_es y ayúdanos a mejorar.' + else: + text = f'Your order with ID {order.id} has finished successfully!⚡ Join us @robosats and help us improve.' + self.send_message(user, text) return def public_order_cancelled(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return - - lang = user.profile.telegram_lang_code - if lang == 'es': - text = f'Hey {order.maker.username}, has cancelado tu orden pública con ID {order.id}.' - else: - text = f'Hey {order.maker.username}, you have cancelled your public order with ID {order.id}.' - - self.send_message(user, text) - return - - def taker_canceled_b4bond(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return - - lang = user.profile.telegram_lang_code - if lang == 'es': - text = f'Hey {order.maker.username}, el tomador ha cancelado antes de bloquear su fianza.' - else: - text = f'Hey {order.maker.username}, the taker has canceled before locking the bond.' - - self.send_message(user, text) - return - - def taker_expired_b4bond(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return - - lang = user.profile.telegram_lang_code - if lang == 'es': - text = f'Hey {order.maker.username}, el tomador no ha bloqueado la fianza a tiempo.' - else: - text = f'Hey {order.maker.username}, the taker has not locked the bond in time.' - - self.send_message(user, text) + if order.maker.profile.telegram_enabled: + lang = order.maker.profile.telegram_lang_code + if lang == 'es': + text = f'Hey {order.maker.username}, has cancelado tu orden pública con ID {order.id}.' + else: + text = f'Hey {order.maker.username}, you have cancelled your public order with ID {order.id}.' + self.send_message(order.maker, text) return def collaborative_cancelled(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return - - lang = user.profile.telegram_lang_code - if lang == 'es': - text = f'Hey {order.maker.username}, tu orden con ID {str(order.id)} fue cancelada colaborativamente.' - else: - text = f'Hey {order.maker.username}, your order with ID {str(order.id)} has been collaboratively cancelled.' - - self.send_message(user, text) + for user in [order.maker, order.taker]: + if user.profile.telegram_enabled: + lang = user.profile.telegram_lang_code + if lang == 'es': + text = f'Hey {user.username}, tu orden con ID {str(order.id)} fue cancelada colaborativamente.' + else: + text = f'Hey {user.username}, your order with ID {str(order.id)} has been collaboratively cancelled.' + self.send_message(user, text) return def dispute_opened(self, order): - user = order.maker - if not user.profile.telegram_enabled: - return - - lang = user.profile.telegram_lang_code - if lang == 'es': - text = f'Hey {order.maker.username}, la orden con ID {str(order.id)} ha entrado en disputa.' - else: - text = f'Hey {order.maker.username}, a dispute has been opened on your order with ID {str(order.id)}.' - - self.send_message(user, text) + for user in [order.maker, order.taker]: + if user.profile.telegram_enabled: + lang = user.profile.telegram_lang_code + if lang == 'es': + text = f'Hey {user.username}, la orden con ID {str(order.id)} ha entrado en disputa.' + else: + text = f'Hey {user.username}, a dispute has been opened on your order with ID {str(order.id)}.' + self.send_message(user, text) return def order_published(self, order): - - time.sleep(1) # Just so this message always arrives after the previous two - - user = order.maker - lang = user.profile.telegram_lang_code - - # In weird cases the order cannot be found (e.g. it is cancelled) - - queryset = Order.objects.filter(maker=user) - order = queryset.last() - - print(str(order.id)) - if lang == 'es': - text = f'Hey {order.maker.username}, tu orden con ID {str(order.id)} es pública en el libro de ordenes.' - else: - text = f"Hey {order.maker.username}, your order with ID {str(order.id)} is public in the order book." - self.send_message(user, text) - user.profile.telegram_welcomed = True - user.profile.save() + if order.maker.profile.telegram_enabled: + lang = order.maker.profile.telegram_lang_code + # In weird cases the order cannot be found (e.g. it is cancelled) + queryset = Order.objects.filter(maker=order.maker) + if len(queryset) == 0: + return + order = queryset.last() + if lang == 'es': + text = f'Hey {order.maker.username}, tu orden con ID {str(order.id)} es pública en el libro de ordenes.' + else: + text = f"Hey {order.maker.username}, your order with ID {str(order.id)} is public in the order book." + self.send_message(order.maker, text) return diff --git a/api/tasks.py b/api/tasks.py index 5557d362..9767961e 100644 --- a/api/tasks.py +++ b/api/tasks.py @@ -272,9 +272,6 @@ def send_message(order_id, message): if message == 'welcome': telegram.welcome(order) - - if message == 'order_taken': - telegram.order_taken(order) elif message == 'order_expired_untaken': telegram.order_expired_untaken(order) @@ -288,9 +285,6 @@ def send_message(order_id, message): elif message == 'taker_expired_b4bond': telegram.taker_expired_b4bond(order) - elif message == 'taker_canceled_b4bond': - telegram.taker_canceled_b4bond(order) - elif message == 'order_published': telegram.order_published(order) diff --git a/api/views.py b/api/views.py index a08cfb46..93ac51c4 100644 --- a/api/views.py +++ b/api/views.py @@ -246,14 +246,11 @@ class OrderView(viewsets.ViewSet): data["price_now"], data["premium_now"] = Logics.price_and_premium_now(order) # 3. c) If maker and Public/Paused, add premium percentile - # num similar orders, and maker information to enable telegram notifications. if data["is_maker"] and order.status in [Order.Status.PUB, Order.Status.PAU]: data["premium_percentile"] = compute_premium_percentile(order) data["num_similar_orders"] = len( Order.objects.filter(currency=order.currency, status=Order.Status.PUB)) - # Adds/generate telegram token and whether it is enabled - data = {**data,**Telegram.get_context(request.user)} # 4) Non participants can view details (but only if PUB) elif not data["is_participant"] and order.status != Order.Status.PUB: @@ -921,6 +918,8 @@ class InfoView(ListAPIView): context["nickname"] = request.user.username context["referral_code"] = str(request.user.profile.referral_code) context["earned_rewards"] = request.user.profile.earned_rewards + # Adds/generate telegram token and whether it is enabled + context = {**context,**Telegram.get_context(request.user)} has_no_active_order, _, order = Logics.validate_already_maker_or_taker( request.user) if not has_no_active_order: diff --git a/docker-compose.yml b/docker-compose.yml index b4ca84f0..8538f54c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -111,6 +111,8 @@ services: environment: REDIS_URL: redis://localhost:6379 command: celery -A robosats beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler + volumes: + - .:/usr/src/robosats depends_on: - redis network_mode: service:tor diff --git a/frontend/src/components/BottomBar.js b/frontend/src/components/BottomBar.js index b4e7ffa2..5942f783 100644 --- a/frontend/src/components/BottomBar.js +++ b/frontend/src/components/BottomBar.js @@ -82,6 +82,9 @@ class BottomBar extends Component { activeOrderId: data.active_order_id ? data.active_order_id : null, lastOrderId: data.last_order_id ? data.last_order_id : null, referralCode: data.referral_code, + tgEnabled: data.tg_enabled, + tgBotName: data.tg_bot_name, + tgToken: data.tg_token, earnedRewards: data.earned_rewards, lastDayPremium: data.last_day_nonkyc_btc_premium, }), @@ -658,6 +661,9 @@ class BottomBar extends Component { activeOrderId={this.props.activeOrderId} lastOrderId={this.props.lastOrderId} referralCode={this.props.referralCode} + tgEnabled={this.props.tgEnabled} + tgBotName={this.props.tgBotName} + tgToken={this.props.tgToken} handleSubmitInvoiceClicked={this.handleSubmitInvoiceClicked} host={this.getHost()} showRewardsSpinner={this.state.showRewardsSpinner} diff --git a/frontend/src/components/Dialogs/EnableTelegram.tsx b/frontend/src/components/Dialogs/EnableTelegram.tsx new file mode 100644 index 00000000..d9525a23 --- /dev/null +++ b/frontend/src/components/Dialogs/EnableTelegram.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useTheme } from '@mui/material/styles'; +import QRCode from 'react-qr-code'; +import { + Dialog, + DialogTitle, + DialogActions, + DialogContent, + DialogContentText, + Button, +} from '@mui/material'; + +interface Props { + open: boolean; + onClose: () => void; + tgBotName: string; + tgToken: string; + onClickEnable: () => void; +} + +const EnableTelegramDialog = ({ + open, + onClose, + tgBotName, + tgToken, + onClickEnable, +}: Props): JSX.Element => { + const { t } = useTranslation(); + const theme = useTheme(); + + return ( + + {t('Enable TG Notifications')} + +
+ + {t( + 'You will be taken to a conversation with RoboSats telegram bot. Simply open the chat and press Start. Note that by enabling telegram notifications you might lower your level of anonymity.', + )} + + + + + + +
+ ); +}; + +export default EnableTelegramDialog; diff --git a/frontend/src/components/Dialogs/Profile.tsx b/frontend/src/components/Dialogs/Profile.tsx index 3838afc5..3c62d220 100644 --- a/frontend/src/components/Dialogs/Profile.tsx +++ b/frontend/src/components/Dialogs/Profile.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useTheme } from '@mui/material/styles'; import { Link as LinkRouter } from 'react-router-dom'; import { @@ -25,7 +26,9 @@ import { Typography, } from '@mui/material'; +import { EnableTelegramDialog } from '.'; import BoltIcon from '@mui/icons-material/Bolt'; +import SendIcon from '@mui/icons-material/Send'; import NumbersIcon from '@mui/icons-material/Numbers'; import PasswordIcon from '@mui/icons-material/Password'; import ContentCopy from '@mui/icons-material/ContentCopy'; @@ -44,6 +47,9 @@ interface Props { activeOrderId: string | number; lastOrderId: string | number; referralCode: string; + tgEnabled: boolean; + tgBotName: string; + tgToken: string; handleSubmitInvoiceClicked: (e: any, invoice: string) => void; host: string; showRewardsSpinner: boolean; @@ -62,6 +68,9 @@ const ProfileDialog = ({ activeOrderId, lastOrderId, referralCode, + tgEnabled, + tgBotName, + tgToken, handleSubmitInvoiceClicked, host, showRewardsSpinner, @@ -73,11 +82,13 @@ const ProfileDialog = ({ handleSetStealthInvoice, }: Props): JSX.Element => { const { t } = useTranslation(); + const theme = useTheme(); const [rewardInvoice, setRewardInvoice] = useState(''); const [showRewards, setShowRewards] = useState(false); const [openClaimRewards, setOpenClaimRewards] = useState(false); const [weblnEnabled, setWeblnEnabled] = useState(false); + const [openEnableTelegram, setOpenEnableTelegram] = useState(false); useEffect(() => { getWebln().then((webln) => { @@ -110,6 +121,11 @@ const ProfileDialog = ({ } }; + const handleClickEnableTelegram = () => { + window.open('https://t.me/' + tgBotName + '?start=' + tgToken, '_blank').focus(); + setOpenEnableTelegram(false); + }; + return ( + setOpenEnableTelegram(false)} + tgBotName={tgBotName} + tgToken={tgToken} + onClickEnable={handleClickEnableTelegram} + /> + + + + + + + + {tgEnabled ? ( + + {t('Telegram enabled')} + + ) : ( + + )} + + + @@ -245,7 +287,7 @@ const ProfileDialog = ({ { - this.setState({ openEnableTelegram: true }); - }; - - handleClickCloseEnableTelegramDialog = () => { - this.setState({ openEnableTelegram: false }); - }; - - handleClickEnableTelegram = () => { - window - .open( - 'https://t.me/' + this.props.data.tg_bot_name + '?start=' + this.props.data.tg_token, - '_blank', - ) - .focus(); - this.handleClickCloseEnableTelegramDialog(); - }; - - EnableTelegramDialog = () => { - const { t } = this.props; - return ( - - {t('Enable TG Notifications')} - -
- - {t( - 'You will be taken to a conversation with RoboSats telegram bot. Simply open the chat and press Start. Note that by enabling telegram notifications you might lower your level of anonymity.', - )} - - - - - - -
- ); - }; - depositHoursMinutes = () => { const hours = parseInt(this.props.data.escrow_duration / 3600); const minutes = parseInt((this.props.data.escrow_duration - hours * 3600) / 60); @@ -565,7 +504,6 @@ class TradeBox extends Component { {/* Make confirmation sound for HTLC received. */} {this.Sound('locked-invoice')} - {this.EnableTelegramDialog()} {t('Your order is public')} {' ' + this.stepXofY()} @@ -591,18 +529,6 @@ class TradeBox extends Component {
- - {this.props.data.tg_enabled ? ( - - {t('Telegram enabled')} - - ) : ( - - )} - @@ -1409,7 +1335,7 @@ class TradeBox extends Component { enterTouchDelay={0} title={ - To open a dispute you need to wait{' '} + To open a dispute you need to wait }