Ejemplo n.º 1
0
async def cancel_offer(call: types.CallbackQuery, offer: EscrowOffer):
    """React to offer cancellation.

    While first party is transferring, second party can't cancel offer,
    because we can't be sure that first party hasn't already completed
    transfer before confirming.
    """
    if offer.trx_id:
        return await call.answer(i18n("cancel_after_transfer"))
    if offer.memo:
        if offer.type == "buy":
            escrow_user = offer.init
        elif offer.type == "sell":
            escrow_user = offer.counter
        if call.from_user.id != escrow_user["id"]:
            return await call.answer(i18n("cancel_before_verification"))
        req = get_escrow_instance(offer[offer.type]).remove_from_queue(
            offer._id)
        req["timeout_handler"].cancel()

    sell_answer = i18n("escrow_cancelled", locale=offer.init["locale"])
    buy_answer = i18n("escrow_cancelled", locale=offer.counter["locale"])
    offer.cancel_time = time()
    await offer.delete_document()
    await call.answer()
    await tg.send_message(offer.init["id"],
                          sell_answer,
                          reply_markup=start_keyboard())
    await tg.send_message(offer.counter["id"],
                          buy_answer,
                          reply_markup=start_keyboard())
    sell_state = FSMContext(dp.storage, offer.init["id"], offer.init["id"])
    buy_state = FSMContext(dp.storage, offer.counter["id"],
                           offer.counter["id"])
    await sell_state.finish()
    await buy_state.finish()
Ejemplo n.º 2
0
async def errors_handler(update: types.Update, exception: Exception):
    """Handle exceptions when calling handlers.

    Send error notification to special chat and warn user about the error.
    """
    if isinstance(exception, MessageNotModified):
        return True

    log.error("Error handling request {}".format(update.update_id),
              exc_info=True)

    chat_id = None
    if update.message:
        update_type = "message"
        from_user = update.message.from_user
        chat_id = update.message.chat.id
    if update.callback_query:
        update_type = "callback query"
        from_user = update.callback_query.from_user
        chat_id = update.callback_query.message.chat.id

    if chat_id is not None:
        try:
            exceptions_chat_id = config.EXCEPTIONS_CHAT_ID
        except AttributeError:
            pass
        else:
            await tg.send_message(
                exceptions_chat_id,
                "Error handling {} {} from {} ({}) in chat {}\n{}".format(
                    update_type,
                    update.update_id,
                    markdown.link(from_user.mention, from_user.url),
                    from_user.id,
                    chat_id,
                    markdown.code(traceback.format_exc(limit=-3)),
                ),
                parse_mode=types.ParseMode.MARKDOWN,
            )
        await tg.send_message(
            chat_id,
            i18n("unexpected_error"),
            reply_markup=start_keyboard(),
        )

    return True
Ejemplo n.º 3
0
async def claim_transfer_custom_address(message: types.Message,
                                        state: FSMContext):
    """Transfer cashback to custom address."""
    data = await state.get_data()
    await tg.send_message(message.chat.id, i18n("claim_transfer_wait"))
    try:
        trx_url = await transfer_cashback(message.from_user.id,
                                          data["currency"], message.text)
    except TransferError:
        await tg.send_message(message.chat.id, i18n("cashback_transfer_error"))
    else:
        await tg.send_message(
            message.chat.id,
            markdown.link(i18n("cashback_transferred"), trx_url),
            parse_mode=ParseMode.MARKDOWN,
            reply_markup=start_keyboard(),
        )
Ejemplo n.º 4
0
async def handle_start_command(message: types.Message, state: FSMContext):
    """Handle /start.

    Ask for language if user is new or show menu.
    """
    user = {"id": message.from_user.id, "chat": message.chat.id}
    result = await database.users.update_one(user, {"$setOnInsert": user}, upsert=True)

    if not result.matched_count:
        await tg.send_message(
            message.chat.id, i18n("choose_language"), reply_markup=locale_keyboard()
        )
        return

    await state.finish()
    await tg.send_message(
        message.chat.id, i18n("help_message"), reply_markup=start_keyboard()
    )
Ejemplo n.º 5
0
async def handle_start_command(message: types.Message, state: FSMContext):
    """Handle /start.

    Ask for language if user is new or show menu.
    """
    user = {
        "id": message.from_user.id,
        "chat": message.chat.id,
        "mention": message.from_user.mention,
        "has_username": bool(message.from_user.username),
    }
    args = message.text.split()
    if len(args) > 1:
        if args[1][0] == "_":
            search_filter = {
                "mention": "@" + args[1][1:],
                "has_username": True
            }
        else:
            search_filter = {"referral_code": args[1]}
        referrer_user = await database.users.find_one(search_filter)
        if referrer_user:
            user["referrer"] = referrer_user["id"]
            if referrer_user.get("referrer"):
                user["referrer_of_referrer"] = referrer_user["referrer"]

    result = await database.users.update_one(
        {
            "id": user["id"],
            "chat": user["chat"]
        }, {"$setOnInsert": user},
        upsert=True)

    if not result.matched_count:
        await tg.send_message(message.chat.id,
                              i18n("choose_language"),
                              reply_markup=locale_keyboard())
        return

    await state.finish()
    await tg.send_message(message.chat.id,
                          i18n("help_message"),
                          reply_markup=start_keyboard())
Ejemplo n.º 6
0
async def set_order(order: MutableMapping[str, Any], chat_id: int):
    """Set missing values and finish order creation."""
    order["start_time"] = time()
    if "duration" not in order:
        order["duration"] = config.ORDER_DURATION_LIMIT
    order["expiration_time"] = time() + order["duration"] * 24 * 60 * 60
    order["notify"] = True
    if "price_sell" not in order and "sum_buy" in order and "sum_sell" in order:
        order["price_sell"] = Decimal128(
            normalize(order["sum_sell"].to_decimal() / order["sum_buy"].to_decimal())
        )
        order["price_buy"] = Decimal128(
            normalize(order["sum_buy"].to_decimal() / order["sum_sell"].to_decimal())
        )

    inserted_order = await database.orders.insert_one(order)
    order["_id"] = inserted_order.inserted_id
    await tg.send_message(chat_id, i18n("order_set"), reply_markup=start_keyboard())
    await show_order(order, chat_id, order["user_id"], show_id=True)
    asyncio.create_task(order_notification(order))
Ejemplo n.º 7
0
async def send_message_to_support(message: types.Message):
    """Format message and send it to support.

    Envelope emoji at the beginning is the mark of support ticket.
    """
    if message.from_user.username:
        username = "******" + message.from_user.username
    else:
        username = markdown.link(message.from_user.full_name,
                                 message.from_user.url)

    await tg.send_message(
        config.SUPPORT_CHAT_ID,
        emojize(":envelope:") +
        f" #chat\\_{message.chat.id} {message.message_id}\n{username}:\n" +
        markdown.escape_md(message.text),
        parse_mode=types.ParseMode.MARKDOWN,
    )
    await tg.send_message(
        message.chat.id,
        i18n("support_response_promise"),
        reply_markup=start_keyboard(),
    )
Ejemplo n.º 8
0
async def validate_offer(call: types.CallbackQuery, offer: EscrowOffer):
    """Ask support for manual verification of exchange."""
    if offer.type == "buy":
        sender = offer.counter
        receiver = offer.init
        currency = offer.sell
    elif offer.type == "sell":
        sender = offer.init
        receiver = offer.counter
        currency = offer.buy

    escrow_instance = get_escrow_instance(offer.escrow)
    answer = "{0}\n{1} sender: {2}{3}\n{1} receiver: {4}{5}\nBank: {6}\nMemo: {7}"
    answer = answer.format(
        markdown.link("Unconfirmed escrow.",
                      escrow_instance.trx_url(offer.trx_id)),
        currency,
        markdown.link(sender["mention"],
                      User(id=sender["id"]).url),
        " ({})".format(sender["name"]) if "name" in sender else "",
        markdown.link(receiver["mention"],
                      User(id=receiver["id"]).url),
        " ({})".format(receiver["name"]) if "name" in receiver else "",
        offer.bank,
        markdown.code(offer.memo),
    )
    await tg.send_message(config.SUPPORT_CHAT_ID,
                          answer,
                          parse_mode=ParseMode.MARKDOWN)
    await offer.delete_document()
    await call.answer()
    await tg.send_message(
        call.message.chat.id,
        i18n("request_validation_promise"),
        reply_markup=start_keyboard(),
    )
Ejemplo n.º 9
0
async def subcribe_to_pair(
    message: types.Message, state: FSMContext, command: Command.CommandObj,
):
    r"""Manage subscription to pairs.

    Currency pair is indicated with two space separated arguments
    after **/subscribe** or **/unsubscribe** in message text. First
    argument is the currency order's creator wants to sell and second
    is the currency order's creator wants to buy.

    Similarly to **/book**, any argument can be replaced with \*, which
    results in subscribing to pairs with any currency in place of the
    wildcard.

    Without arguments commands show list of user's subscriptions.
    """
    source = message.text.upper().split()

    if len(source) == 1:
        user = await database.subscriptions.find_one({"id": message.from_user.id})
        sublist = ""
        if user:
            for i, sub in enumerate(user["subscriptions"]):
                sublist += "\n{}. {} → {}".format(
                    i + 1,
                    sub["sell"] if sub["sell"] else "*",
                    sub["buy"] if sub["buy"] else "*",
                )
        if sublist:
            answer = i18n("your_subscriptions") + sublist
        else:
            answer = i18n("no_subscriptions")
        await tg.send_message(message.chat.id, answer, reply_markup=start_keyboard())
        return

    try:
        sell, buy = source[1], source[2]
        sub = {"sell": None, "buy": None}
        if sell != "*":
            sub["sell"] = sell
        if buy != "*":
            sub["buy"] = buy
    except IndexError:
        await tg.send_message(
            message.chat.id,
            i18n("no_currency_argument"),
            reply_markup=start_keyboard(),
        )
        return

    if command.command[0] == "s":
        update_result = await database.subscriptions.update_one(
            {"id": message.from_user.id},
            {
                "$setOnInsert": {"chat": message.chat.id},
                "$addToSet": {"subscriptions": sub},
            },
            upsert=True,
        )
        if not update_result.matched_count or update_result.modified_count:
            await tg.send_message(
                message.chat.id,
                i18n("subscription_added"),
                reply_markup=start_keyboard(),
            )
        else:
            await tg.send_message(
                message.chat.id,
                i18n("subscription_exists"),
                reply_markup=start_keyboard(),
            )
    elif command.command[0] == "u":
        delete_result = await database.subscriptions.update_one(
            {"id": message.from_user.id}, {"$pull": {"subscriptions": sub}}
        )
        if delete_result.modified_count:
            await tg.send_message(
                message.chat.id,
                i18n("subscription_deleted"),
                reply_markup=start_keyboard(),
            )
        else:
            await tg.send_message(
                message.chat.id,
                i18n("subscription_delete_error"),
                reply_markup=start_keyboard(),
            )
    else:
        raise AssertionError(f"Unknown command: {command.command}")
Ejemplo n.º 10
0
async def default_message(message: types.Message):
    """React to message which has not passed any previous conditions."""
    await tg.send_message(message.chat.id,
                          i18n("unknown_command"),
                          reply_markup=start_keyboard())