• Как сделать ссылку на телеграм с текстом?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Никак. Возможности deep linking у Телеграма довольно разнообразны, но передать текст пользователю никак нельзя. Можно только передать текст боту, причём исключительно как аргумент команды start.

    Подробнее в официальной документации: https://core.telegram.org/api/links
    Ответ написан
    Комментировать
  • Как почистить папку с 246к папок по ssh?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Можно использовать xargs, он сам поделит список аргументов, переданных через stdin, на такие блоки, чтобы они вписывались в лимит. Чтобы не было спецэффектов от всяких особых символов, можно использовать find -print0 | xargs -0 (символ с кодом 0 будет разделять имена файлов вместо стандартного переноса строки):

    find условия -print0|xargs -0 rm -rf

    Однако GNU find сам умеет удалять файлы с помощью -delete:

    find условия -delete

    Ещё может быть проблема, что подобная операция помешает работе сайтов из-за нагрузки на диск, это можно решить с помощью приоритетов для процессов (nice) и ввода-вывода (ionice), тогда удаление будет по возможности выполняться в фоне:

    nice -n19 ionice -c3 команда

    (Если используется find|xargs, то это нужно передать xargs)
    Ответ написан
    Комментировать
  • Старый коммит отвязался от ветки origin/master. Как его туда вернуть?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Почему это "отвязался"? Всё на месте https://github.com/boluchevskii/englishmakerNEW/co...

    Конечно же, HEAD в master и origin/master указывает только на faaefef - так и должно быть. Не может HEAD указывать на два разных коммита.
    Ответ написан
    Комментировать
  • Почему запрос SQL не проходит без GROUP BY?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Потому что это азы SQL: если в выражении есть и агрегирующая функция, и просто неагрегируемые значения, то необходимо явным образом указать, что нужно по ним группировать.
    Ответ написан
    3 комментария
  • Как ускорить рассылку через phpmailer?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    500-1000 секунд это 6-12 минут примерно. Это вообще не тот масштаб, за который имеет смысл волноваться. Рассылается и ладно...
    Ответ написан
    Комментировать
  • Как принимать сообщения с вотсапп?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Есть два способа (на самом деле три):

    1. Пойти по легальному пути. Зарегать бизнес-аккаунт у Facebook, пройти верификацию, зарегистрировать WhatsApp-номер, подключить интеграцию через какого-нибудь провайдера API и работать через него. Характерный признак - только для бизнесов, не очень гуманная цена (5-10-15 тыс. рублей только за подключение - легко), рассылка возможна только по одобренным заранее шаблонам. Но зато легально. Для серьёзного бизнеса с большим количеством клиентов наилучший вариант.

    2. Пойти по серому пути. У WhatsApp есть Web-версия, народ её расковыривает и учится посылать в Web запросы напрямую, без браузера. Есть как сторонние поставщики такого доступа с вменяемым API (их много, не буду рекламить), так и готовые реализации, в том числе на гитхабе (но надо искать актуальную, чтобы работала). Характерный признак такой интеграции - нужно сканировать QR-код для привязки веб-аккаунта к мобильному приложению, а если пользоваться сторонним посредником, то его цена невелика и не имеет жёстких лимитов по числу сообщений. Есть некоторый риск бана аккаунта, поскольку официально так нельзя, но если быть очень осторожным и не спамить (только отвечать на входящие) - то риск бана минимальный (но я бы всё равно не советовал свой основной и очень важный номер в это впутывать). Такое нередко используют всякие мелкие интернет-магазинчики.

    3. Есть ещё оооочень серый путь. На самом деле можно найти полученные реверс-инжинирингом реализации протокола WA, а также ключи, выдранные из официального клиента последних версий. Но за такое очень легко и быстро можно получить бан аккаунта, так что настоятельно не рекомендую (один знакомый потестировал и получил бан аккаунта - к счастью, не основного - чуть ли не в тот же день).

    Для первого пути надо смотреть API конкретного поставщика (они разные), для второго найти подходящую актуальную библиотеку с недавними обновлениями или подходящего агрегатора с его собственным API. Третий - лучше не надо.

    PS: Flask, ngrok - это всё фигня. Надо начать с того, через что делать эту интеграцию. В браузерном WhatsApp Web нет никакого flask, но сообщения ходят.
    Ответ написан
    5 комментариев
  • Woocommerce не отправляет письма на Gmail.com, что делать?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Он же прямо пишет, в чём проблема: SPF-запись для pndexam.ru не предполагает отправку с 45.12.19.68. И это действительно так:

    SPF детали
    pndexam.ru descriptive text "v=spf1 include:_spf.yandex.ru include:beget.com ~all"
    beget.com descriptive text "v=spf1 include:_spf1.beget.ru include:_spf2.beget.ru include:_spf3.beget.ru -all"
    _spf1.beget.com descriptive text "v=spf1 ip4:91.106.200.0/21 ip4:5.101.152.0/21 ip4:185.50.24.0/22 ip4:185.78.28.0/22 ip4:87.236.16.0/22 ip4:87.236.20.0/23 ip4:45.12.16.0/24 ip4:45.12.17.0/24 -all"
    _spf2.beget.com descriptive text "v=spf1 ip4:81.200.112.0/22 ip4:81.200.116.0/23 ip4:81.200.118.0/24 ip4:217.172.24.0/22 ip4:185.19.204.0/22 ip4:193.200.72.0/23 ip4:45.67.56.0/22 -all"
    _spf3.beget.com descriptive text "v=spf1 ip4:193.200.75.0/24 ip4:213.139.208.0/22 ip4:95.214.60.0/23 ip4:193.176.77.0/24 ip4:193.176.76.0/24 ip4:5.181.110.0/24 ip4:5.181.111.0/24 -all"


    Тут есть 45.12.16.0/24 45.12.17.0/24, но нет 45.12.19.0/24. Можно в свою SPF-запись добавить ip4:45.12.19.68. А включать весь beget.com плохо: так можно разрешить куче клиентов beget рассылать почту от домена pndexam.ru.

    Ещё он там DKIM упоминает, это следующий пункт из списка "чего надо проверить".
    Ответ написан
    Комментировать
  • Как правильно оформить код для телеграмм бота (калькулятор систем счисления) с кнопками?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В функции bot_message надо проверять обе кнопки:
    if message.text == 'текст первой кнопки':
        ...
    elif message.text == 'текст второй кнопки':
        ...
    else:
        bot.send_message(message.chat.id, 'Моя твоя не понимать...')


    Сейчас же обрабатывает только одну, вторая не обрабатывается.

    Далее нетрудно заметить, что в коде два раза объявляются функции с одинаковыми именами. Последующее определение перекроет предыдущее, и работать будут только последние.

    Вообще говоря, мне кажется не очень осмысленным делать два варианта перевода между системами счисления. Не лучше ли спросить основание исходной и конечной и затем провести преобразование в общем случае? Заодно можно научиться делать перевод между произвольными системами счисления вплоть до 36-ричной? 10 арабских цифр плюс ещё 26 символов латиницы можно использовать как цифры, и даже формула для всех букв алфавита ord(i) - ord('A') + 10 будет хорошо работать...
    Ответ написан
    1 комментарий
  • Как сделать так,чтобы при отправке любого сообщения бот реагировал?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Тут аж несколько проблем.

    Зачем бот отправляет пользователю пустое сообщение? Скорее всего, на это выскочит ошибка.

    Зачем секция вызова поллинга бота засунута в обработчик, а не находится в основном теле бота? Такой бот просто молча завершится.

    Зачем сравнивать строку message.text с модулем random? Всегда будет False, очевидно же.

    Весьма настоятельно рекомендую учебник и получение элементарных знаний. Даже тривиальный бот совсем без функционала вызывает такие огромные проблемы при написании, и это явно неслучайно.
    Ответ написан
    Комментировать
  • Возможно ли узнать список файлов доступных для загрузки, если страница с прямой ссылкой на их скачивание удалена, но прямая ссылка работает?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В общем случае - нет, нельзя. Но кое-что сделать можно.

    Во-первых, можно посмотреть в Web Archive наличие страниц и даже самих файлов. Не всегда удаётся, но всё же.

    Во-вторых, если файлы были доступны недавно, то можно попытаться поискать их в кэше поисковика. Например, можно поискать "altered_state.zip site:fatapejungle.com"

    В данном случае всё это не помогает, но в других случаях может помочь. Например, я как-то восстанавливал из веб-архива и частично из кэша гугла один удалённый в результате конфликта среди его владельцев сайт.
    Ответ написан
    Комментировать
  • Callback-кнопка в модуле telebot (язык python) не обновляет свое содержание. Что делать?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Потому что при каждом вызове sayanswer будет создаваться новый обработчик callback_query_handler(func=lambda callback: callback.data), добавляясь к списку уже имеющихся. И естественно, что тот, который "застолбил" позицию первым, будет вызываться до скончания жизни запущенного бота. И естественно, что в нём значение url будет таким, каким было при первом запуске sayanswer.

    Главная ошибка тут в том, что НЕЛЬЗЯ внутри функции объявлять другие функции, не понимая чётко, зачем это нужно. Иногда так делают для решения конкретных задач. Но в данном случае это совершенно не нужно и создаёт незапланированное поведение. Функцию check выносим на уровень выше. И не используем в ней переменные из функции sayanswer. Если нужно что-то передать в check - передаём через callback_data.

    Например, можно передать "btn1:кот". В check использовать декоратор с фильтром func=lambda callback: callback.data.startswith("btn1:"). В самой функции откусывать btn1: от начала и уже только тогда формировать запрос к внешнему сервису.
    Ответ написан
    Комментировать
  • Как сделать чтобы один State реагировал на два хендлера?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Если это сторонний API, который не выполняет следующий запрос до завершения текущего, то бесполезно что-то у себя ковырять, всё равно пока запрос первого не будет обработан, запрос второго обрабатывать не начнёт. Тут ничего уже не поможет.

    Если же проблема в том, что обращение к API делается синхронным кодом... Ну так это и надо лечить. Например, если API работает по протоколу http, то меняем библиотеку requests (или что там используется?) на aiohttp. Тогда следующий запрос может выполняться до завершения уже начатого.
    Ответ написан
    Комментировать
  • Как исправить ошибку sqlite3.IntegrityError: UNIQUE constraint failed: users.user_id?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Нет, эта ошибка возникает при INSERT либо UPDATE, если в результате операции в таблице users появятся две записи с одинаковым user_id. От SELECT такого быть не может. Я бы рекомендовал всё же проверить точный номер нужной строки, чтобы убедиться в этом.

    Чтобы этого не происходило, нужно уметь следить за тем, чтобы пользователи второй раз не вставлялись таблицу или чтобы их id не изменялись на конфликтующие при UPDATE. Но тут, скорее всего, влияет только INSERT. Вот с ним и надо делать аккуратно, вставлять только новых пользователей, а если пользователь уже есть - ничего не делать либо обновлять имеющуюся запись (смотря как именно требуется для логики приложения).

    Как вариант, можно сделать совсем по-простому: вместо INSERT использовать REPLACE, который комбинирует INSERT и UPDATE - если при вставке запись с таким id уже есть и случается ошибка, то фактически выполняется UPDATE соответствующей записи с изменением всех перечисленных полей. Например, для REPLACE INTO users (user_id, referrer_id) фактически выполнится что-то типа UPDATE users SET referrer_id=... WHERE user_id=...
    Ответ написан
    Комментировать
  • Как получить кол-во просмотров на посте в тг, с помощью тг бота (node js)?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Никак. Боты работают на событиях: пришло сообщение, человек вступил в группу... Получать историческую информацию по сообщениям невозможно.

    Достать такую информацию можно только с помощью клиентского API (MTProto).
    Ответ написан
    2 комментария
  • Почему Zabbix agent подключается к не понятным IP?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    172.17.0.1 это обычно локальный IP интерфейса docker0. Вся сеть 172.17.0.0/24.

    Модно посмотреть вывод ip addr list dev docker0 и docker network ls, чтобы убедиться.
    Ответ написан
    4 комментария
  • Aiogram бот выдаёт ошибку. TypeError: rezume() missing 1 required positional argument: 'message' что делать?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Потому что плохо читаем документацию. Потому что копипастим куски кода без понимания как они работают.

    message_handler принимает один аргумент - Message.

    callback_query_handler принимает один аргумент - CallbackQuery.

    Тут зачем-то в callback_query_handler два аргумента - call и message. Но бот-то вызывает его так, как и требуется по документации - с одним аргументом. И python обоснованно жалуется, что второй аргумент (message) не передавался.

    До кучи, никогда (НИКОГДА!) нельзя объявлять новые handler'ы внутри имеющихся. Это работает не так, как ты думаешь, и может вызвать очень забавные глюки. Вообще, я не знаю, где люди такому учатся, но на этом сайте с таким приходят регулярно.

    Например...
    Если есть в двух разных функциях-обработчиках "верхнего уровня" есть обработчики с одинаковым фильтром в декораторе (вариант: обработчики могут покрывать общее подмножество случаев), то бот зарегистрирует первым тот "суб-обработчик", для которого "верхнеуровневый обработчик" вызвался первым. В итоге другой обработчик не будет вызываться вообще никогда, а поведение бота может быть весьма неожиданным.


    Далее, в обработчике надо ответить пользователю, установить следующее состояние и сразу же завершить работу этого обработчика. Всю дальнейшую обработку следует выполнять в следующих обработчиках. А сейчас в этом коде все вопросы задаются подряд в одной и той же функции по имени rezume подряд, безо всякого ожидания ответа от пользователя. Короче, сейчас в коде полная лажа, так работать не будет вообще никак.

    PS: Слово "резюме" по-английски пишется совсем не так.
    Ответ написан
    Комментировать
  • Как сделать чтобы бот запоминал следующее сообщение после слеш-команды?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В общем случае это плохая идея. А вдруг сообщение напишет другой пользователь, чем отправил команду?

    Правильнее использовать параметры, лучше с type hinting, чтобы Discord сам подсказывал параметры и приводил типы. Примерно так:

    @bot.slash_command(name='set', description='...')
    async def settings(ctx, selected_channel: discord.Channel):
        await ctx.send(f"Вы выбрали канал {selected_channel.mention}")
    Ответ написан
    6 комментариев
  • Код Telegram бота на компьютере работает нормально, залил на хостинг, парсер не работает, выдаёт ошибку, что делать?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В бесплатных тарифах на pythonanywhere ограничен список адресов, к которым можно обращаться:

    https://www.pythonanywhere.com/whitelist/

    Указанного адреса нет (но есть похожие). Может, надо обращться к одному из похожих?
    Ответ написан
    3 комментария
  • Как взять часть url и подставить в proxy_pass?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Смотрим в документации варианты синтаксиса location. Например, можно сделать так:

    location ~ ^/api-test/(.*)$ {
        proxy_pass http://10.0.0.247:8170/api/service/$1$is_args$args;
    }


    Советую не спешить копипастить, а всё же прочитать и так не слишком длинную документацию. Чтобы лучше понимать, как это работает, и реализовать оптимальным для своей задачи образом.
    Ответ написан
    Комментировать
  • Как сделать регистрацию команд из базы данных Disnake.py?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В документации disnake (впрочем, и в discord.py тоже) какая-то ерунда написана. Вот как выглядит описание Command.__init__ в коде:

    def __init__(
            self,
            func: CommandCallback[CogT, ContextT, P, T],
            **kwargs: Any,
        ) -> None:
    
        ...
    
        self.callback = func


    То есть callback на самом деле это обязательный позиционный параметр.
    Ответ написан
    2 комментария