Exemple #1
0
    async def handle(self, message: types.Message, user: UserRepository,
                     _: dict, state: FSMContext, logger: LoggerAdapter):
        account_id = message.text

        await state.finish()

        if (validate_uuid4(account_id)):
            user_account = await user.get_accounts(message.from_user.id)

            exist_account = next(
                (acc
                 for acc in user_account if str(acc.account_id) == account_id),
                None)

            if (not exist_account):
                async with EmcdClient(account_id, logger) as client:
                    account = await client.get_info()

                    if (account):
                        await user.add_account(message.from_user.id,
                                               account_id, account.username)

                        coins_api = account.get_coins()

                        for coin in await user.get_coins(message.from_user.id):
                            c = coins_api[coin.coin_id]
                            await user.add_account_coin(
                                message.from_user.id, account_id, coin.coin_id,
                                c, coin.is_enabled)

                        await message.answer(_['account_added'].format(
                            account_name=account.username))

                        return
            else:
                await message.answer(_['account_id_already_registered'].format(
                    account_name=exist_account.username))

                return

        keyboard_markup = types.InlineKeyboardMarkup(row_width=1)

        keyboard_markup.add(
            types.InlineKeyboardButton(
                _['again_button'],
                callback_data=menu_cb.new(id='_', type="account",
                                          action='new'),
            ))

        await message.answer(_['account_id_invalid'],
                             reply_markup=keyboard_markup)
async def payouts_info_callback_handler(
    query: types.CallbackQuery,
    callback_data: typing.Dict[str, str],
    user: UserRepository,
    _: LangHolder,
    logger: logging.Logger,
):
    account_id = callback_data["id"]
    coind_id = callback_data['type']
    page = int(callback_data['page'])

    coin_name = Coin(coind_id).name.lower()

    keyboard_markup = types.InlineKeyboardMarkup(row_width=2)

    account = next(
        (acc for acc in await user.get_accounts(query.from_user.id)
         if str(acc.account_id) == account_id),
        None,
    )

    if (account is None):
        await query.answer()
        return await reply_to_account_not_found(query.message, _)

    payouts = None
    async with EmcdClient(account_id, logger) as client:
        payouts = await client.get_payouts(coind_id)

    if (payouts is None):
        await query.answer()
        logger.warning('payouts is none')
        return

    message_text = _['payouts']

    buttons = []

    if (page > 1):
        buttons.append(
            types.InlineKeyboardButton(
                _["prev_button"],
                callback_data=payouts_cb.new(
                    id=account_id,
                    page=page - 1,
                    type=coind_id,
                ),
            ), )

    if (payouts.payouts):
        buttons.append(
            types.InlineKeyboardButton(
                f"{page}/{ceil(len(payouts.payouts) / PER_PAGE_PAYOUTS)}",
                callback_data="do_nothing"), )

    if (payouts):
        for payout in payouts.payouts[(page - 1) * PER_PAGE_PAYOUTS:page *
                                      PER_PAGE_PAYOUTS]:
            message_text += '\n' + _['payouts_template'].format(
                datetime=payout.gmt_time,
                amount=payout.amount,
                transaction_link=
                (f'<a href="https://blockchair.com/{coin_name}/transaction/{payout.txid}">{payout.txid[8:]}</a>'
                 ) if payout.txid else _['no_link'])

        if (len(payouts.payouts) > page * PER_PAGE_PAYOUTS):
            buttons.append(
                types.InlineKeyboardButton(
                    _["next_button"],
                    callback_data=payouts_cb.new(
                        id=account_id,
                        page=page + 1,
                        type=coind_id,
                    ),
                ), )

    keyboard_markup.row(*buttons)
    action_type = SELECT_COIN_CB

    coins = [
        coin for coin in await user.get_account_coins(
            query.from_user.id, account_id) if coin.is_active
    ]

    if (len(coins) == 1
        ):  #in case if enabled only one coin we treat them as default
        action_type = coins[0].coin_id

    keyboard_markup.row(
        types.InlineKeyboardButton(
            _["income_stat_button"],
            callback_data=income_cb.new(
                id=account_id,
                page=1,
                type=coind_id,
            ),
        ),
        types.InlineKeyboardButton(
            _['back_to_account_button'],
            callback_data=menu_cb.new(
                id=account.account_id, type="account", action='open'),
        ) if len(coins) == 1 else types.InlineKeyboardButton(
            _["back_to_payouts"],
            callback_data=finance_cb.new(
                id=account_id,
                type=action_type,
                action=SELECT_COIN_CB,
                page=
                page,  #id=account_id, type=coin.coin_id, action=, page=page,
            ),
        ),
    )

    await query.message.edit_text(
        message_text,
        reply_markup=keyboard_markup,
        disable_web_page_preview=True,
    )
    await query.answer()
Exemple #3
0
async def worker_info_callback_handler(
    query: types.CallbackQuery,
    callback_data: typing.Dict[str, str],
    user: UserRepository,
    _: dict,
    logger: logging.Logger,
):
    account_id = callback_data["id"]
    coind_id = callback_data['type']
    page = int(callback_data['page'])
    status_id = int(callback_data['status_id'])

    keyboard_markup = types.InlineKeyboardMarkup(row_width=2)

    workers = None
    async with EmcdClient(account_id, logger) as client:
        workers = await client.get_workers(coind_id)

    if (workers is None):
        await query.answer()
        logger.warning('workers is none')
        return

    message_text = ""

    buttons = []

    if (page > 1):
        buttons.append(
            types.InlineKeyboardButton(
                _["prev_button"],
                callback_data=worker_cb.new(
                    id=account_id, page=page - 1, type=coind_id, status_id=status_id,
                ),
            ),
        )

    workers_normalized = workers.get_all_workers_by_status(0, status_id)

    if (workers_normalized):
        buttons.append(
            types.InlineKeyboardButton(
                f"{page}/{ceil(len(workers_normalized) / PER_PAGE_WORKERS)}",
                callback_data="do_nothing"
            ),
        )


    locales = {
        'hashrate': _['hashrate'],
        'current': _['current'],
        '1_hour': _['1_hour'],
        '24_hour': _['24_hour'],
    }

    if (workers):
        for worker in workers_normalized[(page - 1) * PER_PAGE_WORKERS: page * PER_PAGE_WORKERS]:
            message_text += '\n' + format_worker_info(worker, locales)

        if (len(workers_normalized) > page * PER_PAGE_WORKERS):
            buttons.append(
                types.InlineKeyboardButton(
                    _["next_button"],
                    callback_data=worker_cb.new(
                        id=account_id, page=page + 1, type=coind_id, status_id=status_id,
                    ),
                ),
            )
        
    keyboard_markup.row(*buttons)
    
    coins = [coin for coin in await user.get_account_coins(query.from_user.id, account_id) if coin.is_active]

    filter_text = _['show_dead_workers']
    new_status_id = WORKER_STATUS_CAROUSEL[status_id]
    if (new_status_id == -1):
        filter_text = _['show_dead_workers']
    elif (new_status_id == 0):
        filter_text = _['show_inactive_workers']
    elif (new_status_id == 1):
        filter_text = _['show_active_workers']
    elif (new_status_id == 3):
        filter_text = _['show_all_workers']

    if (len(coins) == 1): #in case if enabled only one coin we treat them as default
        keyboard_markup.row(
            types.InlineKeyboardButton(
                filter_text,
                callback_data=worker_cb.new(
                    id=account_id, page=page, type=coind_id, status_id=new_status_id,
                ),
            ),
            types.InlineKeyboardButton(
                _["cabinet"],
                callback_data=menu_cb.new(
                    id=account_id, type="account", action="open",
                ),
            ),
        )
    else:
        keyboard_markup.row(
            types.InlineKeyboardButton(
                filter_text,
                callback_data=worker_cb.new(
                    id=account_id, page=page, type=coind_id, status_id=new_status_id,
                ),
            ),
            types.InlineKeyboardButton(
                _["back_to_workers"],
                callback_data=worker_cb.new(
                    id=account_id, page=page, type=SELECT_COIN_CB, status_id=status_id,
                ),
            ),
        )
        

    workers_all = workers.get_all_workers(0)

    await query.message.edit_text(
        _['worker_info_descr'].format(
            hashrate=format_rate(workers.total_hashrate.hashrate),
            hashrate1h=format_rate(workers.total_hashrate.hashrate1_h),
            hashrate24h=format_rate(workers.total_hashrate.hashrate24_h),
            total=str(len(workers_all)) + (_['show_workers_filter_pointer'] if status_id == 3 else ''),
            dead=str(len([i for i in workers_all if i.status_id == -1])) + (_['show_workers_filter_pointer'] if status_id == -1 else ''),
            active=str(len([i for i in workers_all if i.status_id == 1])) + (_['show_workers_filter_pointer'] if status_id == 1 else ''),
            inactive=str(len([i for i in workers_all if i.status_id == 0])) + (_['show_workers_filter_pointer'] if status_id == 0 else ''),
            description=message_text,
        ),
        reply_markup=keyboard_markup,
    )
    await query.answer()
    async def job(self, con: Connection, item: AccountCoinNotificationWorker,
                  notifier: TelegramNotifier, locales: Dict):
        now = datetime.now()

        message_text = ''
        user_repo = UserRepository(con)
        notification_repo = NotificationRepository(con)

        async with EmcdClient(item.account_id, logger) as client:
            api_account = await client.get_workers(item.coin_id)
            if (api_account is None):
                logger.info(f'{item.account_id}|{item.coin_id} - is none')
                return

            user_account = next(
                (acc for acc in await user_repo.get_accounts(item.user_id)
                 if acc.account_id == item.account_id), None)

            logger.info(
                f'{item.account_id}|{item.coin_id} - Scraped worker info')
            workers = api_account.get_all_workers(item.id)

            await user_repo.update_account_coin(item.id, item.user_id,
                                                item.account_id, item.coin_id,
                                                item.address, api_account,
                                                item.is_active, now)

            logger.info(
                f'{item.account_id}|{item.coin_id} - Total workers count {len(workers)}'
            )

            if (workers):
                user_db = await user_repo.get_user(item.user_id)

                user_locale = Lang(user_db.lang_id)
                translation = locales[user_locale.name]

                change_status_descr = []
                blacklisted_workers = [
                    w.worker_id for w in await
                    user_repo.get_blacklisted_workers(item.user_id)
                ]

                previous_worker_state = await user_repo.get_previous_worker_state_for_account(
                    item.id)
                for worker in workers:
                    previous_state = next((w for w in previous_worker_state
                                           if w.worker_id == worker.worker),
                                          None)
                    if (previous_state):
                        if (previous_state.status_id != worker.status_id):
                            logger.info(
                                f'{item.account_id}|{item.coin_id} - worker changed status {worker.worker}'
                            )
                            if (worker.worker not in blacklisted_workers):
                                change_status_descr.append(
                                    WorkerChangeStatusDataModel(
                                        previous_state.status_id,
                                        worker.status_id,
                                        previous_state.worker_id))
                            else:
                                logger.info(
                                    f'{item.account_id}|{item.coin_id} - {worker.worker} blacklisted'
                                )
                                if (worker.status_id == -1):
                                    logger.info(
                                        f'{item.account_id}|{item.coin_id} - {worker.worker} dead, need to delete from blacklist'
                                    )
                                    await user_repo.toggle_worker_blacklist(
                                        item.user_id, worker.worker)

                logger.info(
                    f'{item.account_id}|{item.coin_id} - Sending notification {item.id}'
                )
                if (change_status_descr):
                    descr = [
                        st.to_description(
                            translation['worker_changed_status_descr'],
                            translation) for st in change_status_descr
                    ]
                    message_text = translation[
                        'worker_changed_status_body'].format(
                            account_name=user_account.username,
                            description='\n'.join([i for i in descr]))

                    await notification_repo.add(message_text,
                                                NotifyType.Worker,
                                                [NotifyChannel.Telegram],
                                                user_db.id)

                logger.info(
                    f'{item.account_id}|{item.coin_id} - Clean up worker history {item.id}'
                )
                await user_repo.cleanup_worker_history_for_account(item.id)

                logger.info(
                    f'{item.account_id}|{item.coin_id} - Storing to database')

                await user_repo.store_coin_account_worker_history(workers, now)
                logger.info(f'{item.account_id}|{item.coin_id} - Stored')
Exemple #5
0
async def statistic_info_callback_handler(
    query: types.CallbackQuery,
    callback_data: typing.Dict[str, str],
    user: UserRepository,
    _: LangHolder,
    logger: logging.Logger,
):
    account_id = callback_data["id"]
    coin_id = callback_data['type']

    keyboard_markup = types.InlineKeyboardMarkup(row_width=2)

    account = next(
        (acc for acc in await user.get_accounts(query.from_user.id)
         if str(acc.account_id) == account_id),
        None,
    )

    if (account is None):
        await query.answer()
        return await reply_to_account_not_found(query.message, _)

    account_coin = next(
        (i
         for i in await user.get_account_coins(query.from_user.id, account_id)
         if i.coin_id == coin_id),
        None,
    )

    buttons = []

    coins = [
        coin for coin in await user.get_account_coins(
            query.from_user.id, account_id) if coin.is_active
    ]

    if (len(coins) == 1
        ):  #in case if enabled only one coin we treat them as default
        buttons.append(
            types.InlineKeyboardButton(
                _["cabinet"],
                callback_data=menu_cb.new(id=account_id,
                                          type="account",
                                          action="open"),
            ), )
    else:
        buttons.append(
            types.InlineKeyboardButton(
                _["back_to_statistic"],
                callback_data=statistic_cb.new(
                    id=account_id,
                    type=SELECT_COIN_CB,
                ),
            ), )

    keyboard_markup.row(*buttons)

    account_api = None
    currency_list = None

    user_currency = await user.get_user_currency(query.from_user.id)

    async with EmcdClient(account_id, logger) as client:
        account_api = await client.get_info()

    if (account_api is None):
        await query.answer()
        logger.warning('account_api is none')
        return

    is_fallback = False

    async with CoinCapClient() as client:
        c_id = coin_id
        if (c_id == 'bchn'):
            c_id = 'bch'

        currency_list = await client.get_info_for_exchange(
            c_id, user_currency.currency_code)

        if (currency_list is None or len(currency_list.data) == 0):
            currency_list = await client.get_info_for_exchange(
                c_id, FALLBACK_CURRENCY)
            is_fallback = True

    if (currency_list is None):
        await query.answer('Please try later, 3rd party service is busy')
        logger.warning('currency_list is none')
        return

    curr = sorted(currency_list.data, key=take_update_timestamp)[0]

    coin_info = account_api.get_coins()[coin_id]

    message_text = ""

    if (is_fallback):
        message_text = _['currency_not_found'].format(
            currency_code=user_currency.currency_code,
            fallback_currency_code=FALLBACK_CURRENCY,
        ) + '\n'

    message_text += _['statistic_descr'].format(
        account_name=account.username,
        address=account_coin.address,
        current_balance=format(coin_info.balance, '.8f'),
        current_balance_dol=format_currency(round(
            coin_info.balance * curr.price_usd, 4),
                                            '',
                                            locale="en_US"),
        current_balance_sec=format_currency(round(
            coin_info.balance * curr.price_quote, 4),
                                            '',
                                            locale="en_US"),
        current_balance_sec_symbol=curr.quote_symbol,
        total_paid=format(coin_info.total_paid, '.8f'),
        total_paid_dol=format_currency(round(
            coin_info.total_paid * curr.price_usd, 4),
                                       '',
                                       locale="en_US"),
        total_paid_sec=format_currency(round(
            coin_info.total_paid * curr.price_quote, 4),
                                       '',
                                       locale="en_US"),
        total_paid_sec_symbol=curr.quote_symbol,
        currency_dol=format_currency(round(curr.price_usd, 2),
                                     '',
                                     locale="en_US"),
        currency_sec=format_currency(round(curr.price_quote, 2),
                                     '',
                                     locale="en_US"),
        currency_sec_symbol=curr.quote_symbol,
    )

    await query.message.edit_text(
        message_text,
        reply_markup=keyboard_markup,
    )
    await query.answer()
    async def job(self, con: Connection, item: AccountCoinNotificationPayout,
                  notifier: TelegramNotifier, locales: Dict):
        user_repo = UserRepository(con)
        notification_repo = NotificationRepository(con)

        async with EmcdClient(item.account_id, logger) as client:
            user_account = next(
                (acc for acc in await user_repo.get_accounts(item.user_id)
                 if acc.account_id == item.account_id), None)

            payouts = await client.get_payouts(item.coin_id)

            if (payouts is None):
                logger.info('payouts is none')
                return

            user_db = await user_repo.get_user(item.user_id)

            actual_payouts = [
                p for p in payouts.payouts
                if p.timestamp > PAYOUTS_CHECK_START_DATETIME and
                p.timestamp > item.notification_update_datetime.timestamp()
                and p.timestamp > item.account_created_datetime.timestamp()
                and p.txid is not None and p.txid != ''
            ]

            if (actual_payouts):
                user_locale = Lang(user_db.lang_id)
                translation = locales[user_locale.name]
                for payout in actual_payouts:
                    is_payout_notified = await user_repo.is_payout_notified(
                        item.id,
                        payout.timestamp,
                    )
                    if (is_payout_notified == False):
                        coin = Coin(item.coin_id)

                        latest_account_data = await client.get_info()
                        if (latest_account_data is None):
                            logger.info('account is none')
                            return

                        latest_coin_data = latest_account_data.get_coins()[
                            item.coin_id]

                        msg_text = translation['new_payout_received'].format(
                            account=user_account.username,
                            link=
                            f'<a href="https://blockchair.com/{coin.name.lower()}/transaction/{payout.txid}">{payout.txid[8:]}</a>',
                            amount=payout.amount,
                            current_balance=format(latest_coin_data.balance,
                                                   '.8f'),
                        )

                        await notification_repo.add(msg_text,
                                                    NotifyType.Payout,
                                                    [NotifyChannel.Telegram],
                                                    user_db.id)

                        await user_repo.mark_payout_as_notified(
                            item.id,
                            payout.timestamp,
                        )
async def income_info_callback_handler(
    query: types.CallbackQuery,
    callback_data: typing.Dict[str, str],
    user: UserRepository,
    _: LangHolder,
    logger: logging.Logger,
):
    account_id = callback_data["id"]
    coind_id = callback_data['type']
    page = int(callback_data['page'])

    keyboard_markup = types.InlineKeyboardMarkup(row_width=2)

    account = next(
        (acc for acc in await user.get_accounts(query.from_user.id)
         if str(acc.account_id) == account_id),
        None,
    )

    if (account is None):
        await query.answer()
        return await reply_to_account_not_found(query.message, _)

    incomes = None
    async with EmcdClient(account_id, logger) as client:
        incomes = await client.get_rewards(coind_id)

    if (incomes is None):
        await query.answer()
        logger.warning('incomes is none')
        return

    message_text = _['income']

    buttons = []

    if (page > 1):
        buttons.append(
            types.InlineKeyboardButton(
                _["prev_button"],
                callback_data=income_cb.new(
                    id=account_id,
                    page=page - 1,
                    type=coind_id,
                ),
            ), )

    if (incomes.income):
        buttons.append(
            types.InlineKeyboardButton(
                f"{page}/{ceil(len(incomes.income) / PER_PAGE_INCOME)}",
                callback_data="do_nothing"), )

    if (incomes):
        for income in incomes.income[(page - 1) * PER_PAGE_INCOME:page *
                                     PER_PAGE_INCOME]:
            message_text += '\n' + _['income_template'].format(
                datetime=income.gmt_time,
                amount=format(income.income, '.8f'),
            )

        if (len(incomes.income) > page * PER_PAGE_INCOME):
            buttons.append(
                types.InlineKeyboardButton(
                    _["next_button"],
                    callback_data=income_cb.new(
                        id=account_id,
                        page=page + 1,
                        type=coind_id,
                    ),
                ), )

    keyboard_markup.row(*buttons)
    action_type = SELECT_COIN_CB

    coins = [
        coin for coin in await user.get_account_coins(
            query.from_user.id, account_id) if coin.is_active
    ]

    if (len(coins) == 1
        ):  #in case if enabled only one coin we treat them as default
        action_type = coins[0].coin_id

    keyboard_markup.row(
        types.InlineKeyboardButton(
            _["payouts_stat_button"],
            callback_data=payouts_cb.new(
                id=account_id,
                page=1,
                type=coind_id,
            ),
        ),
        types.InlineKeyboardButton(
            _['back_to_account_button'],
            callback_data=menu_cb.new(
                id=account.account_id, type="account", action='open'),
        ) if len(coins) == 1 else types.InlineKeyboardButton(
            _["back_to_income"],
            callback_data=finance_cb.new(
                id=account_id,
                type=action_type,
                action=SELECT_COIN_CB,
                page=
                page,  #id=account_id, type=coin.coin_id, action=, page=page,
            ),
        ),
    )

    await query.message.edit_text(
        message_text,
        reply_markup=keyboard_markup,
    )
    await query.answer()
Exemple #8
0
async def black_list_info_callback_handler(
    query: types.CallbackQuery,
    callback_data: typing.Dict[str, str],
    user: UserRepository,
    _: dict,
    logger: logging.Logger,
    state: FSMContext,
):
    account_id = callback_data["id"]
    coin_id = callback_data['type']
    action = callback_data['action']
    page = int(callback_data['page'])

    if (action != '_'):
        async with state.proxy() as data:
            worker_id = data.get('workers_unique', {}).get(action, None)
            if (worker_id):
                is_blacklisted = await user.toggle_worker_blacklist(
                    query.from_user.id, worker_id)
                await query.answer(_['worker_blacklisted' if is_blacklisted
                                     else 'worker_not_blacklisted'].format(
                                         worker=worker_id, ))
            else:
                logger.warning(
                    f'worker_id was null {data.get("workers_unique")}')
                await query.answer(
                    'If you see this message please contact with support',
                    show_alert=True)

    keyboard_markup = types.InlineKeyboardMarkup(row_width=2)

    blacklisted_workers = [
        w.worker_id
        for w in await user.get_blacklisted_workers(query.from_user.id)
    ]

    workers = None
    async with EmcdClient(account_id, logger) as client:
        workers = await client.get_workers(coin_id)

    if (workers is None):
        await query.answer()
        logger.warning('workers is none')
        return

    buttons = []

    buttons_workers = []

    if (page > 1):
        buttons.append(
            types.InlineKeyboardButton(
                _["prev_button"],
                callback_data=worker_black_cb.new(id=account_id,
                                                  page=page - 1,
                                                  type=coin_id,
                                                  action="_"),
            ), )

    workers_normalized = workers.get_all_workers(0, )

    if (workers_normalized):
        buttons.append(
            types.InlineKeyboardButton(
                f"{page}/{ceil(len(workers_normalized) / PER_PAGE_BLACK_LIST)}",
                callback_data="do_nothing"), )

        async with state.proxy() as data:
            data['workers_unique'] = generate_unique_workers_dict(
                workers_normalized)

        for worker in workers_normalized[(page - 1) *
                                         PER_PAGE_BLACK_LIST:page *
                                         PER_PAGE_BLACK_LIST]:
            buttons_workers.append(
                types.InlineKeyboardButton(
                    worker.worker + (_["blacklist_pointer"] if worker.worker
                                     in blacklisted_workers else ""),
                    callback_data=worker_black_cb.new(
                        id=account_id,
                        page=page,
                        type=coin_id,
                        action=worker.hash_name()),
                ), )

        if (len(workers_normalized) > page * PER_PAGE_BLACK_LIST):
            buttons.append(
                types.InlineKeyboardButton(
                    _["next_button"],
                    callback_data=worker_black_cb.new(id=account_id,
                                                      page=page + 1,
                                                      type=coin_id,
                                                      action="_"),
                ), )

    for w_row in grouper(2, buttons_workers):
        keyboard_markup.row(*w_row)

    keyboard_markup.row(*buttons)

    coins = [
        coin for coin in await user.get_account_coins(
            query.from_user.id, account_id) if coin.is_active
    ]
    if (len(coins) == 1
        ):  #in case if enabled only one coin we treat them as default
        keyboard_markup.row(
            types.InlineKeyboardButton(
                _["cabinet"],
                callback_data=menu_cb.new(
                    id=account_id,
                    type="account",
                    action="open",
                ),
            ), )
    else:
        keyboard_markup.row(
            types.InlineKeyboardButton(
                _["back_to_workers_blacklist"],
                callback_data=worker_black_cb.new(
                    id=account_id,
                    page=page,
                    type=SELECT_COIN_CB,
                    action="_",
                ),
            ), )

    await query.message.edit_text(
        _['worker_blacklist_descr'].format(
            b_count=len(blacklisted_workers),
            pointer=_["blacklist_pointer"],
        ),
        reply_markup=keyboard_markup,
    )
    await query.answer()