Задать вопрос
  • Как сделать нумерацию начинающуюся с нуля каждый год?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Самое простое решение такое. Делаем sequence, из которого при вставке заполняем нужный номер явным вызовом nextval или дефолтным значением/триггером. И каждый год 1 января сбрасываем sequence в 0. Зачем слишком усложнять-то?
    Ответ написан
  • Почему перемещение объявления и инициализации переменной на новую строчку кода влияет на результат работы программы?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В этом коде есть важная ошибка. В циклах for нигде не задано начальное значение переменной i, поэтому она может иметь любое значение, её поведение неопределено. Например, она может выделиться там же, где была выделена предыдущая, поэтому i во втором цикле будет равна последнему значению в предыдущем, то есть 10, даже если в первом цикле повезло попасть на 0.

    Локальные переменные как правило выделяются в стеке, поэтому если между двумя for стоит определение ещё одной переменной, то она, вероятно, выделится на месте i. И поэтому новая переменная i попадёт в другую часть стека, где, если повезёт, будет 0.

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

    Решение простое: надо везде в циклах for указать начальное значение i, тогда всё станет нормально, и перестановка определения count перестанет создавать такие совсем не странные эффекты.
    Ответ написан
    3 комментария
  • Как сделать, чтобы бизнес-аккаунт выглядел вот так, а не просто номер вверху?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Нужно зарегаться официально через одного из партнёров WA https://www.facebook.com/business/partner-director..., предоставить документы и пройти верификацию для "зелёной галочки". Дальше работать через API этого партнёра либо через какую-то готовую интеграцию (их есть для разных CRM, чат-ботов итд).

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

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Никак нельзя. Это же мечта любого спамера - чтобы пользователь не мог избежать действия.
    Ответ написан
    Комментировать
  • Как удалить последние 2 сообщения в телеграм боте?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Никак, бот может удалять только свои сообщения, но не сообщения от пользователя.
    Ответ написан
  • Где можно хранить данные, которые тг-бот использует в работе?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Хранить картинки в git-репе проекта - это обычно плохая идея, кроме случаев, когда их совсем немного. Хранить их в каталоге рядом с ботом - нормальная.

    Но если картинки для разных пользователей будут повторяться, то лучше запоминать file_id ранее загруженных, чтобы в следующий раз не отправлять сами файлы. Это ускорит отправку, да и Телеграму лишние копии файлов на их серверах ни к чему.

    spoiler
    У меня есть бот, у которого в репе лежит несколько картинок, плюс он помнит в своей базе, какие уже отправлял, чтобы передавать их только по file_id https://github.com/shurshur/glagolitic-bot/blob/ma...
    Ответ написан
    Комментировать
  • Как скопировать файл на ext4 image без прав root?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Да, можно, используя debugfs:

    $ dd if=/dev/zero of=test.img bs=1M count=10
    $ mkfs.ext4 test.img
    $ debugfs -w test.img
    debugfs: write my_file.txt new_file.txt
    Ответ написан
    1 комментарий
  • Как привязать postgis к postgres в docker?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Нужно просто использовать образ postgis вместо образа postgres. Образ postgis/postgis унаследован от postgres и вполне его заменяет.
    Ответ написан
    2 комментария
  • Как решить проблему, если телеграм-бот выдаёт ошибку Task exception was never retrieved и не отправляет файл в чат повторно?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Дело в том, что photo это file handle, после того файл один раз прочитан, его надо переоткрыть заново сначала. Так что надо считывать прям внутри обработчика, а не снаружи.
    Ответ написан
    Комментировать
  • Как исправить код на Python?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Сейчас запущено два бота с одним токеном одновременно либо, как вариант, что-то идёт не так при запросе, и бот делает второй-третий-четвёртый запрос getUpdates слишком часто. Но я думаю что скорее всего первый вариант, ибо это довольно частая ошибка новичков.
    Ответ написан
    Комментировать
  • Почему хандлер не срабатывает повторно?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Этот бот очень странно написан, и вообще непонятно, как в нём хоть что-то работает.

    Начнём с того, что вот это:

    global operator
    operator = call.message.chat.id


    будет означать, что в переменной operator всегда будет id чата последнего оператора, нажавшего кнопку join_dialog_btn. Аналогично будут проблемы с user_help_id. В итоге не будет это одновременно работать ни с несколькими операторами, ни с несколькими пользователями.

    Далее, НЕ НАДО создавать в функции другие функции без чёткого понимания, зачем это нужно, и тем более не надо их оборачивать регистрирующими декораторами. Это работает совсем не так, как кажется.

    Когда оператор Вася получит своего первого пользователя, будет вызван декоратор @bot.message_handler(func=lambda message: message.from_user.id == Вася). После того, как Вася отработает по пользователю и получит следующего, будет создан ещё один обработчик с таким же декоратором, но так как один такой обработчик (с такими условиями) уже в цепочке есть, то будет вызван первый, который полагается на локальные переменные от предыдущего вызова supportWait. Довольно заметно, что ты с этим уже сталкивался и именно поэтому локальные переменные (operator и user_help_id) сделал глобальными, но это, разумеется, не поможет, так как абсолютно неправильно.

    Что тут надо сделать?

    1. Вынести все обработчики на верхний уровень и избавиться от дурной практики регистрации их через декораторы внутри функции каждый раз при их вызове.

    2. Отделить логику оператора от логики пользователя - это следует делать отдельными обработчиками со своей логикой.

    3. Где-то хранить соответствие chat_id пользователя - chat_id назначенного оператора. Можно завести словарь, но в целом можно и через FSM Телебота (но тогда нельзя будет отслеживать, что пользователя уже кто-то взял).

    4. Не забывать, что пользователь может успеть оставить несколько сообщений до того, как оператор примет запрос - их все нужно не потерять.

    Можно сделать примерно так:

    spoiler
    operator_ids = [список id операторов]
    
    @bot.message_handler(func=lambda message: message.chat.id in operator_ids)
    def handle_operator_message(message):
    # обработка сообщения оператора в состоянии, когда ему ничего не назначено
    # можно например ругнуться чтобы ждал появления обращений
    
    # состояния пользователей, в частности чтобы накапливать сообщения от начала обращения
    # до назначения оператора
    user_states = {}
    
    @bot.message_handler(func=lambda message: True)
    def handle_user_message(message):
    # обработка сообщения пользователя в состоянии, когда он только что обратился
        # посылаем сообщение с кнопкой всем операторам
        # (задача со звёздочкой: всем операторам, у которых никто не назначен)
        # в кнопке передаём callback_data=join_dialog_btn:CHAT_ID_ПОЛЬЗОВАТЕЛЯ
        # запоминаем сообщение
        user_states[message.chat.id] = {"messages":[message]}
        # затем регистрируем отдельный обработчик
        bot.register_next_step_handler(message, handle_user_unassigned)
    
    # обработчик собирает сообщения пользователя
    def handle_user_unassigned(message, user_data):
        user_states[message.chat.id]["messages"].append(message)
    
    # обработчик сообщений пользователя после назначения оператора
    # этот обработчик выставится из обработчика сообщения оператора.
    # используя register_next_step_handler_by_chat_id
    def handle_user_assigned(message, operator_id):
        # посылаем сообщение оператору (operator_id)
    
    def handle_operator_assigned(message, user_id):
        # посылаем сообщение юзеру (user_id)
    
    # в кнопке передаётся chat_id пользователя
    # в принципе, можно в кнопку засунуть больше данных, в том числе json до 64 символов
    @bot.callback_query_handler(func=lambda call: call.data.startswith('join_dialog_btn:'))
        user_chat_id = int(call.data.split(":")[1])
        for operator_id in operators_id:
            if operator_id != call.chat.id:
                 # посылаем остальным операторам "пользователя взял в работу оператор Вася"
        # также выплёвываем все накопленные сообщения пользователя этому оператору
        for msg in user_states[user_chat_id]["messages"]:
             # тут делаем forward_message
        # выставляем обработчик оператору
        bot.register_next_step_handler(message, handler_operator_assigned, user_chat_id)
        # теперь надо переключить пользователя на оператора, используя его chat_id
        bot.register_next_step_handler_by_chat_id(user_chat_id, handle_user_assigned, call.chat.id)
        # обрати внимание, что это выставляет обработчик юзеру, а не оператору!
    
    # в итоге всей этой конструкции в чате operator_id действует обработчик handle_operator_assigned
    # с параметром user_id, а в чате user_id - handle_user_assigned с параметром operator_id, и можно
    # в них сразу посылать полученные сообщения (только не forward_message, конечно,
    # чтобы не светить имя оператора)


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

    spoiler
    Важно отметить, что полноценные взрослые чат-сервисы делают совершенно не так. В них обычно даже не используется Telegram, вместо этого оператор работает через web-интерфейс (а может и отдельное приложение), в котором можно контролировать всю историю взаимодействия, переключаться между пользователями (нормальная ситуация если оператор ведёт нескольких пользователей параллельно), подтягивать данные из CRM/клиентской базы, интегрировать справочники типовых ответов или чат-ботов, итд итп. Также, например, нормальные обработки таймаутов (если пользователь или оператор не отвечает в нужный срок...)

    И делать это лучше, например, на брокерах очередей (типа rabbitmq). Чтобы не нужно было вот этого замороченного собирания сообщений до назначения оператора в какой-то список и не было риска, что пользователь успеет что-то ещё написать в процессе назначения оператору.
    Ответ написан
  • Проблема с ботом discord на python?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    С некоторых пор API Discord больше не позволяет по умолчанию ботам видеть содержимое сообщений. Нужно явно запросить message_content intents:

    intents.message_content = True

    А также надо включить privileged intents в developer portal для этого бота.
    Ответ написан
    3 комментария
  • Как сделать так, что бы бот на disnake увидел мемберов?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Необходимо добавить member intents. А также включить privileged intents в настройках бота в developer portal. Документация. Вообще, примеров на эту тему в интернете море.
    Ответ написан
    Комментировать
  • Как получить цвет пользователя в telegram на python?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Если в Bot API нет такой информации, то никак. А в Bot API её на текущйи момент вообще нет. Можно только узнать о наличии premium-подписки. https://core.telegram.org/bots/api#user
    Ответ написан
    2 комментария
  • Как перенаправить вывод strace в tail?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Нет, так сделать нельзя, но есть утилиты, которыми можно принять через stdin лог и автоматически его ротировать по размеру (в том числе удаляя старые файлы). Например, multilog.

    Примеры есть тут: https://superuser.com/questions/291368/log-rotatio...

    Но в целом strace - это так себе средство отладки, тем более скриптов, лучше логгировать в самом скрипте, потому что в strace много ненужного мусора. Как вариант, можно с помощью опций ограничить системные вызовы, которые он будет логгировать.
    Ответ написан
    Комментировать
  • Можно ли получать обновления с телеграм канала через Telegram API без добавления бота в этот канал?

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

    С помощью клиентского API можно подписываться на чужие каналы и получать с них обновления, но это делается с реквизитами пользователя (своего) и канал должен быть публичным, чтобы на него можно было легко подписаться.

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

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Это спам и всё делается ради вон того файла во вложении. Текст такой чтобы повысить его уникальность и усложнить его ловлю спам-фильтром.
    Ответ написан
    Комментировать
  • Как удалить своего бота из чужой группы Телеграм?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Да, это можно, используя метод leaveChat. Достаточно id группы знать.

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

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В Bot API - никак. Этот API работает на событиях и не позволяет получать информацию по ранее отправленным сообщениям, и события вида "что-то изменилось в числе просмотров" не предусмотрено.

    Только пользоваться клиентским API (MTProto) на базе библиотеки telethon или pyrogram. Изображать из себя обычного пользователя и смотреть историю сообщений в канале.
    Ответ написан
    Комментировать
  • Есть ли универсальный модуль Python для работы с разными базами данных (mysql, postgresql, ...)?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    sqlalchemy вполне можно использовать как абстрактный интерфейс к базам данных, просто передавая в него строковые запросы без ORM.
    Ответ написан
    1 комментарий