├── requirements.txt ├── .gitignore ├── teamSpeakTelegram ├── __main__.py ├── locale │ └── es │ │ └── LC_MESSAGES │ │ ├── teamspeak.mo │ │ └── teamspeak.po ├── __init__.py ├── teamspeak.py └── utils.py ├── setup.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | python-telegram-bot 2 | ts3 3 | pymysql 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | __pycache__/ 3 | config.ini 4 | *.db 5 | *.sql 6 | build/ 7 | dist/ 8 | *.egg-info/ -------------------------------------------------------------------------------- /teamSpeakTelegram/__main__.py: -------------------------------------------------------------------------------- 1 | from teamSpeakTelegram import teamspeak 2 | 3 | if __name__ == '__main__': 4 | teamspeak.main() -------------------------------------------------------------------------------- /teamSpeakTelegram/locale/es/LC_MESSAGES/teamspeak.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jossalgon/teamSpeakTelegram/HEAD/teamSpeakTelegram/locale/es/LC_MESSAGES/teamspeak.mo -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='teamSpeakTelegram', 4 | version='0.8.1', 5 | description='A telegram bot that tells you who is connected to the teamspeak server to know when your friends are online.', 6 | url='https://github.com/jossalgon/teamSpeakTelegram', 7 | author='Jose Luis Salazar Gonzalez', 8 | author_email='joseluis25sg@gmail.com', 9 | packages=['teamSpeakTelegram'], 10 | package_data={'teamSpeakTelegram': ['locale/es/LC_MESSAGES/*']}, 11 | install_requires=[ 12 | "python-telegram-bot", 13 | "ts3", 14 | "pymysql" 15 | ], 16 | zip_safe=False) 17 | -------------------------------------------------------------------------------- /teamSpeakTelegram/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from functools import wraps 3 | 4 | import gettext 5 | 6 | import sys 7 | from telegram.ext import Filters 8 | 9 | 10 | # Config the translations 11 | try: 12 | path = os.path.join(os.path.dirname(sys.modules['teamSpeakTelegram'].__file__), "locale") 13 | lang_es = gettext.translation("teamspeak", localedir=path, languages=["es"]) 14 | except OSError: 15 | lang_es = gettext 16 | 17 | _lang = gettext.gettext 18 | 19 | 20 | def _(msg): return _lang(msg) 21 | 22 | 23 | def user_language(func): 24 | @wraps(func) 25 | def wrapper(bot, update, *args, **kwargs): 26 | global _lang 27 | 28 | if update.effective_user.language_code.startswith('es'): 29 | # If language is es_ES, translates 30 | _lang = lang_es.gettext 31 | else: 32 | _lang = gettext.gettext 33 | 34 | result = func(bot, update, *args, **kwargs) 35 | return result 36 | return wrapper 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TeamSpeakTelegram 2 | TeamSpeakTelegram is a telegram bot that tells you who is connected to the teamspeak server to know when your friends are online. It can be used both in private and in a group chat. 3 | 4 | 5 | ## Installing 6 | 1. Install or upgrade teamSpeakTelegram from pip: 7 | ``` 8 | $ pip install teamSpeakTelegram --upgrade 9 | ``` 10 | Or you can install from source: 11 | ``` 12 | $ git clone https://github.com/jossalgon/teamSpeakTelegram.git 13 | $ cd teamSpeakTelegram 14 | $ python setup.py install 15 | ``` 16 | 17 | 2. Create a config.ini file with: 18 | ``` 19 | [Telegram] 20 | token_id = YOUR_TELEGRAM_BOT_TOKEN 21 | admin_id = YOUR_TELEGRAM_ID 22 | 23 | [TS] 24 | ts_host = YOUR_TS_HOST 25 | ts_user = serveradmin (OR YOUR TS USERNAME AS ADMIN) 26 | ts_pass = YOUR_TS_PASSWORD 27 | 28 | [Database] 29 | DB_HOST = YOUR_MYSQL_HOST 30 | DB_USER = YOUR_MYSQL_USER 31 | DB_PASS = YOUR_MYSQL_PASS 32 | DB_NAME = YOUR_MYSQL_DB_NAME 33 | ``` 34 | If you don't know your telegram id, leave it blank, start the bot and use the command /id. 35 | 36 | 3. Run the bot 37 | ``` 38 | python3 -m teamSpeakTelegram 39 | ``` 40 | 41 | 4. Invite users 42 | 43 | Use the command /generate to generate invitation links, the users logged with this link could use the bot. 44 | 45 | 46 | ## Commands 47 | Command | Uses 48 | ------- | ----- 49 | /start | Reply with a welcome message 50 | /who | Reply with the connected users 51 | /ts | Reply with the channels and connected users 52 | /mention | Join to receive a forwarded messsage if contains @flandas 53 | /generate | Generate an invitation link 54 | /id | Reply with your telegram id 55 | /notify | Send a message with the args received from the command to all the telegram users 56 | /users | Manage users with intuitive buttons 57 | /groups | Manage user groups with intuitive buttons 58 | /gm | Send a global message to your teamSpeak server 59 | 60 | 61 | /user command | User detail 62 | :------------------------------------------:|:-------------------------------------------: 63 | ![TS command](http://imgur.com/giUiHUb.png) | ![TS command](http://imgur.com/uyjMQHz.png) 64 | 65 | /ts command | 66 | :------------------------------------------: 67 | ![TS command](http://imgur.com/KJ41dUK.png) | -------------------------------------------------------------------------------- /teamSpeakTelegram/teamspeak.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from telegram import InlineKeyboardButton 3 | from telegram import InlineKeyboardMarkup 4 | from telegram import ReplyKeyboardRemove 5 | from telegram.ext import CallbackQueryHandler 6 | from telegram.ext import ConversationHandler 7 | from telegram.ext import Filters 8 | from telegram.ext import MessageHandler 9 | from telegram.ext import Updater, CommandHandler, RegexHandler 10 | import logging 11 | import configparser 12 | 13 | from teamSpeakTelegram import utils, user_language, _ 14 | 15 | config = configparser.ConfigParser() 16 | config.read('config.ini') 17 | 18 | TOKEN_ID = config.get('Telegram', 'token_id') if config.has_option('Telegram', 'token_id') else None 19 | ADMIN_ID = config.getint('Telegram', 'admin_id') if config.has_option('Telegram', 'admin_id') else None 20 | TS_HOST = config['TS']['ts_host'] 21 | 22 | 23 | logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) 24 | 25 | logger = logging.getLogger(__name__) 26 | 27 | 28 | @user_language 29 | def start(bot, update, args): 30 | message = update.message 31 | user = message.from_user 32 | res = False 33 | 34 | link = "http://www.teamspeak.com/invite/%s/" % TS_HOST 35 | reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton(_('Connect TS'), url=link)]]) 36 | 37 | if args: 38 | res = utils.validate_invitation_token(token=args[0], user_id=user.id, name=user.first_name) 39 | 40 | if res: 41 | text = _("Welcome %s you're now activated, using /who or /ts you can check who's in teamspeak.") % \ 42 | user.first_name 43 | elif utils.is_allow(user.id): 44 | text = _("Hello %s, using /who or /ts you can check who's in teamspeak.") % user.first_name 45 | else: 46 | reply_markup = None 47 | text = _("Welcome, ask admin to generate an invitation link by /generate") 48 | bot.sendMessage(message.chat_id, text, reply_to_message_id=message.message_id, reply_markup=reply_markup) 49 | 50 | 51 | @user_language 52 | def ts_stats(bot, update): 53 | message = update.message 54 | if utils.is_allow(message.from_user.id): 55 | stats = utils.ts_stats(bot, update) 56 | else: 57 | stats = _("You aren't allow to use this") 58 | bot.send_message(message.chat.id, stats, reply_to_message_id=message.message_id) 59 | 60 | 61 | @user_language 62 | def generate_invitation(bot, update): 63 | message = update.message 64 | token = utils.generate_invitation() 65 | link = 'https://telegram.me/%s?start=%s' % (bot.username, token) 66 | share_link = 'https://telegram.me/share/url?url={0}&text=Click%20the%20link%20to%20join%20the%20teamspeak%20bot'.format(link) 67 | keyboard = [[InlineKeyboardButton(_('Join'), url=link)], 68 | [InlineKeyboardButton(_('Share link'), url=share_link)]] 69 | reply_markup = InlineKeyboardMarkup(keyboard) 70 | bot.sendMessage(message.chat_id, '🎈 ' + _('Welcome to TeamSpeak bot') + ' 🎈\n\n' + 71 | _('This is an invitation to use the TeamSpeak bot'), 72 | reply_markup=reply_markup) 73 | 74 | 75 | @user_language 76 | def mention_toggle(bot, update): 77 | message = update.message 78 | if not utils.is_allow(message.from_user.id): 79 | text = _("You aren't allow to use this") 80 | elif message.chat.type == 'private': 81 | text = _('Use this command in the group where you want to activate/disable the notifications') 82 | else: 83 | text = utils.mention_toggle(bot, update, message.chat_id, message.from_user.id) 84 | bot.sendMessage(message.chat_id, text, reply_to_message_id=message.message_id) 85 | 86 | 87 | def get_id(bot, update): 88 | message = update.message 89 | bot.sendMessage(message.chat_id, message.from_user.id, reply_to_message_id=message.message_id) 90 | 91 | 92 | def notify(bot, update, args): 93 | text = ' '.join(args) 94 | text = text.replace('\\n', '\n') 95 | if text: 96 | for user_id in utils.get_user_ids(): 97 | try: 98 | bot.send_message(user_id, text, parse_mode='Markdown') 99 | except: 100 | pass 101 | 102 | 103 | def cancel(bot, update): 104 | message = update.message 105 | bot.sendMessage(chat_id=message.chat_id, text=_('Global text has been cancelled.'), 106 | reply_to_message_id=message.message_id, reply_markup=ReplyKeyboardRemove(selective=True)) 107 | return ConversationHandler.END 108 | 109 | 110 | def log_error(bot, update, error): 111 | logger.warning('Update "%s" caused error "%s"' % (update, error)) 112 | 113 | 114 | def filter_assign_alias(msg): 115 | return msg.reply_to_message and \ 116 | msg.reply_to_message.from_user.id == msg.bot.id and \ 117 | msg.reply_to_message.text_markdown.startswith('🙍‍♂️') 118 | 119 | 120 | @user_language 121 | def unknown(bot, update): 122 | bot.sendMessage(chat_id=update.message.chat_id, text=_("Sorry, I didn't understand that command.")) 123 | 124 | 125 | def main(): 126 | utils.create_database() 127 | 128 | updater = Updater(token=TOKEN_ID) 129 | 130 | # Get the dispatcher to register handlers 131 | dp = updater.dispatcher 132 | 133 | # on different commands - answer in Telegram 134 | dp.add_handler(CommandHandler('start', start, pass_args=True)) 135 | dp.add_handler(CommandHandler('help', start)) 136 | dp.add_handler(CommandHandler('who', ts_stats)) 137 | dp.add_handler(CommandHandler('ts', utils.ts_view)) 138 | dp.add_handler(CommandHandler('mention', mention_toggle)) 139 | dp.add_handler(CommandHandler('generate', generate_invitation, Filters.user(user_id=ADMIN_ID))) 140 | dp.add_handler(CommandHandler('notify', notify, Filters.user(user_id=ADMIN_ID), pass_args=True)) 141 | dp.add_handler(CommandHandler('id', get_id)) 142 | dp.add_handler(RegexHandler(r'(?i).*\@flandas\b', utils.mention_forwarder)) 143 | dp.add_handler(CallbackQueryHandler(utils.callback_query_handler, pass_chat_data=True)) 144 | dp.add_handler(CommandHandler('users', utils.send_users_tsdb, Filters.user(user_id=ADMIN_ID), pass_chat_data=True)) 145 | dp.add_handler(CommandHandler('groups', utils.send_ts_groups, Filters.user(user_id=ADMIN_ID), pass_chat_data=True)) 146 | dp.add_handler(MessageHandler(filter_assign_alias, utils.assign_user_alias_step2, pass_chat_data=True)) 147 | 148 | gm_handler = ConversationHandler( 149 | allow_reentry=True, 150 | entry_points=[CommandHandler('gm', utils.pre_send_gm)], 151 | states={ 152 | 0: [MessageHandler(Filters.text, utils.send_gm)], 153 | }, 154 | 155 | fallbacks=[CommandHandler('cancel', cancel), CommandHandler('headshot', cancel)] 156 | ) 157 | dp.add_handler(gm_handler) 158 | 159 | # Add response for unknown private messages 160 | dp.add_handler(MessageHandler(Filters.private, unknown)) 161 | 162 | # log all errors 163 | dp.add_error_handler(log_error) 164 | 165 | # Start the Bot 166 | updater.start_polling() 167 | 168 | # Run the bot until the you presses Ctrl-C or the process receives SIGINT, 169 | # SIGTERM or SIGABRT. This should be used most of the time, since 170 | # start_polling() is non-blocking and will stop the bot gracefully. 171 | updater.idle() 172 | 173 | 174 | if __name__ == '__main__': 175 | main() 176 | -------------------------------------------------------------------------------- /teamSpeakTelegram/locale/es/LC_MESSAGES/teamspeak.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR ORGANIZATION 3 | # FIRST AUTHOR , YEAR. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: \n" 8 | "POT-Creation-Date: 2017-08-18 17:02+0200\n" 9 | "PO-Revision-Date: 2017-08-18 17:03+0200\n" 10 | "Language-Team: \n" 11 | "MIME-Version: 1.0\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Content-Transfer-Encoding: 8bit\n" 14 | "Generated-By: pygettext.py 1.5\n" 15 | "X-Generator: Poedit 1.8.7.1\n" 16 | "Last-Translator: \n" 17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 18 | "Language: es\n" 19 | 20 | #: utils.py:143 21 | msgid "Update" 22 | msgstr "Actualizar" 23 | 24 | #: utils.py:153 utils.py:1063 teamspeak.py:57 teamspeak.py:79 25 | msgid "You aren't allow to use this" 26 | msgstr "No se te permite usar esto\t" 27 | 28 | #: utils.py:196 29 | msgid "Users online:" 30 | msgstr "Conectados:" 31 | 32 | #: utils.py:198 33 | msgid "There is no one right now" 34 | msgstr "No hay nadie ahora mismo" 35 | 36 | #: utils.py:247 37 | msgid "Activated mentions" 38 | msgstr "Menciones activadas" 39 | 40 | #: utils.py:250 41 | msgid "Disabled mentions" 42 | msgstr "Menciones desactivadas" 43 | 44 | #: utils.py:491 45 | msgid "User banned successfully" 46 | msgstr "Usuario baneado correctamente" 47 | 48 | #: utils.py:510 49 | msgid "User unbanned successfully" 50 | msgstr "Usuario desbaneado correctamente" 51 | 52 | #: utils.py:535 53 | msgid "User kicked successfully" 54 | msgstr "Usuario kickeado correctamente" 55 | 56 | #: utils.py:537 57 | msgid "Something went wrong" 58 | msgstr "Algo fue mal" 59 | 60 | #: utils.py:555 61 | msgid "User added successfully" 62 | msgstr "Usuario añadido correctamente" 63 | 64 | #: utils.py:576 65 | msgid "User deleted from group successfully" 66 | msgstr "Usuario eliminado del grupo correctamente" 67 | 68 | #: utils.py:585 utils.py:590 utils.py:599 69 | msgid "Page" 70 | msgstr "Pág." 71 | 72 | #: utils.py:595 73 | msgid "Prev" 74 | msgstr "Ant" 75 | 76 | #: utils.py:596 77 | msgid "Next" 78 | msgstr "Sig" 79 | 80 | #: utils.py:635 utils.py:698 81 | msgid "No results" 82 | msgstr "Sin resultados" 83 | 84 | #: utils.py:649 85 | msgid "Ok, give me an *alias* for that user" 86 | msgstr "Ok, dame un *alias* para ese usuario" 87 | 88 | #: utils.py:689 89 | msgid "Skip" 90 | msgstr "Saltar" 91 | 92 | #: utils.py:692 93 | msgid "Ok, is this user on Telegram?" 94 | msgstr "Ok, ¿está este usuario en Telegram?" 95 | 96 | #: utils.py:724 97 | msgid "Alias assigned successfully" 98 | msgstr "Alias asignado correctamente" 99 | 100 | #: utils.py:733 utils.py:742 101 | msgid "*Group list:*" 102 | msgstr "*Listado de grupos:*" 103 | 104 | #: utils.py:734 105 | msgid "" 106 | "Here is a list of your TeamSpeak groups, pressing any of them will take you " 107 | "to his detail." 108 | msgstr "" 109 | "Aquí se muestra un listado de sus grupos de TeamSpeak, presione cualquiera " 110 | "para llevarle a sus detalles." 111 | 112 | #: utils.py:743 113 | msgid "" 114 | "Here is the TeamSpeak group list of this user, pressing any of them will " 115 | "take you to his detail." 116 | msgstr "" 117 | "Aquí se muestra un listado de los grupos de TeamSpeak de este usuario, " 118 | "presione cualquiera para llevarle a sus detalles." 119 | 120 | #: utils.py:745 utils.py:774 utils.py:795 utils.py:816 utils.py:836 121 | #: utils.py:886 122 | msgid "Back" 123 | msgstr "Atrás" 124 | 125 | #: utils.py:767 126 | msgid "Access to default group is forbidden" 127 | msgstr "Acceso a grupos por defecto restringido" 128 | 129 | #: utils.py:770 130 | msgid "group:" 131 | msgstr "grupo:" 132 | 133 | #: utils.py:771 134 | msgid "List users" 135 | msgstr "Listar usuarios" 136 | 137 | #: utils.py:772 138 | msgid "Add user" 139 | msgstr "Añadir usuario" 140 | 141 | #: utils.py:773 142 | msgid "Delete user" 143 | msgstr "Eliminar usuario" 144 | 145 | #: utils.py:785 146 | msgid "*Group users:*" 147 | msgstr "*Usuarios del grupo:*" 148 | 149 | #: utils.py:786 150 | msgid "" 151 | "Here is a list of all users in this group, pressing any of them will take " 152 | "you to his detail." 153 | msgstr "" 154 | "Aquí se muestra un listado de todos los usuarios en este grupo, presione " 155 | "cualquiera para llevarle a sus detalles." 156 | 157 | #: utils.py:806 158 | msgid "*Select an user to add to the group:*" 159 | msgstr "*Seleccione un usuario para añadir al grupo:*" 160 | 161 | #: utils.py:826 162 | msgid "*Select an user to delete from group:*" 163 | msgstr "*Seleccione un usuario para eliminar del grupo:*" 164 | 165 | #: utils.py:845 166 | msgid "*User list:*" 167 | msgstr "*Listado de usuarios:*" 168 | 169 | #: utils.py:846 170 | msgid "" 171 | "Here is a list of all your TeamSpeak users, pressing any of them will take " 172 | "you to his detail." 173 | msgstr "" 174 | "Aquí se muestra un listado de todos sus usuarios de TeamSpeak, presione " 175 | "cualquiera para llevarle a sus detalles." 176 | 177 | #: utils.py:863 178 | msgid "ID banned" 179 | msgstr "ID banneado" 180 | 181 | #: utils.py:863 182 | msgid "ID unbanned" 183 | msgstr "ID desbaneado" 184 | 185 | #: utils.py:868 186 | msgid "IP banned" 187 | msgstr "IP banneado" 188 | 189 | #: utils.py:868 190 | msgid "IP unbanned" 191 | msgstr "IP desbaneado" 192 | 193 | #: utils.py:875 194 | msgid "Name banned" 195 | msgstr "Nombre banneado" 196 | 197 | #: utils.py:875 198 | msgid "Name unbanned" 199 | msgstr "Nombre desbanneado" 200 | 201 | #: utils.py:880 202 | msgid "Channel kick" 203 | msgstr "Expulsar del canal" 204 | 205 | #: utils.py:881 206 | msgid "Server kick" 207 | msgstr "Expulsar del servidor" 208 | 209 | #: utils.py:884 210 | msgid "Assign alias" 211 | msgstr "Asignar alias" 212 | 213 | #: utils.py:885 214 | msgid "Groups" 215 | msgstr "Grupos" 216 | 217 | #: utils.py:891 218 | msgid "ONLINE" 219 | msgstr "CONECTADO" 220 | 221 | #: utils.py:891 222 | msgid "since" 223 | msgstr "desde" 224 | 225 | #: utils.py:894 226 | msgid "*Name:*" 227 | msgstr "*Nombre:*" 228 | 229 | #: utils.py:894 230 | msgid "*User details:*" 231 | msgstr "*Detalles:*" 232 | 233 | #: utils.py:896 234 | msgid "*Last connection:*" 235 | msgstr "*Últ. conexión*" 236 | 237 | #: utils.py:897 238 | msgid "*Last IP:*" 239 | msgstr "*Última IP:*" 240 | 241 | #: utils.py:898 242 | msgid "*Client DB identifier:*" 243 | msgstr "*Identificador de BD:*" 244 | 245 | #: utils.py:899 246 | msgid "*Client Unique identifier:*" 247 | msgstr "*ID de usuario:*" 248 | 249 | #: utils.py:900 250 | msgid "*Date creation:*" 251 | msgstr "*Fecha de creación:*" 252 | 253 | #: utils.py:902 254 | msgid "*Total connections:*" 255 | msgstr "*Conexiones totales:*" 256 | 257 | #: utils.py:929 258 | msgid "No changes" 259 | msgstr "Sin cambios" 260 | 261 | #: utils.py:932 262 | msgid "Successfully updated" 263 | msgstr "Actualizado correctamente" 264 | 265 | #: utils.py:935 266 | msgid "You must be admin" 267 | msgstr "Debes ser administrador" 268 | 269 | #: utils.py:1058 270 | msgid "" 271 | "Ok, what message do you want to send?\n" 272 | "Use /cancel to cancel the command." 273 | msgstr "" 274 | "De acuerdo, ¿que mensaje desea enviar?\n" 275 | "Usa /cancel para cancelar el comando actual." 276 | 277 | #: utils.py:1073 278 | msgid "Global message has been sent to server successfully." 279 | msgstr "El mensaje global ha sido enviado al servidor con éxito." 280 | 281 | #: teamspeak.py:35 282 | msgid "Connect TS" 283 | msgstr "Conectar TS" 284 | 285 | #: teamspeak.py:41 286 | msgid "" 287 | "Welcome %s you're now activated, using /who or /ts you can check who's in " 288 | "teamspeak." 289 | msgstr "" 290 | "Bienvenido %s ya estás activado, usando /who o /ts puedes comprobar quién " 291 | "hay en teamSpeak." 292 | 293 | #: teamspeak.py:44 294 | msgid "Hello %s, using /who or /ts you can check who's in teamspeak." 295 | msgstr "Hola %s, usando /who o /ts puedes comprobar quién hay en teamspeak." 296 | 297 | #: teamspeak.py:47 298 | msgid "Welcome, ask admin to generate an invitation link by /generate" 299 | msgstr "" 300 | "Bienvenido, pide al administrador que genere un enlace de invitación " 301 | "mediante /generate" 302 | 303 | #: teamspeak.py:67 304 | msgid "Join" 305 | msgstr "Unirse" 306 | 307 | #: teamspeak.py:68 308 | msgid "Share link" 309 | msgstr "Compartir enlace" 310 | 311 | #: teamspeak.py:70 312 | msgid "Welcome to TeamSpeak bot" 313 | msgstr "Bienvenido al bot de TeamSpeak" 314 | 315 | #: teamspeak.py:71 316 | msgid "This is an invitation to use the TeamSpeak bot" 317 | msgstr "Esta es una invitación para usar el bot de TeamSpeak" 318 | 319 | #: teamspeak.py:81 320 | msgid "" 321 | "Use this command in the group where you want to activate/disable the " 322 | "notifications" 323 | msgstr "" 324 | "Usa este comando en el grupo donde desees activar/desactivar las " 325 | "notificaciones" 326 | 327 | #: teamspeak.py:105 328 | msgid "Global text has been cancelled." 329 | msgstr "El mensaje global ha sido cancelado." 330 | 331 | #: teamspeak.py:122 332 | msgid "Sorry, I didn't understand that command." 333 | msgstr "Lo siento, no entiendo ese comando." 334 | -------------------------------------------------------------------------------- /teamSpeakTelegram/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import math 3 | import pymysql 4 | import ts3 5 | from telegram import ForceReply 6 | from telegram import TelegramError 7 | from telegram.ext import ConversationHandler 8 | from ts3.examples.viewer import ChannelTreeNode 9 | from telegram import InlineKeyboardButton 10 | from telegram import InlineKeyboardMarkup 11 | from datetime import datetime 12 | from ts3.query import TS3QueryError 13 | import configparser 14 | import logging 15 | import uuid 16 | 17 | from teamSpeakTelegram import user_language, _ 18 | 19 | config = configparser.ConfigParser() 20 | config.read('config.ini') 21 | ts_host = config['TS']['ts_host'] 22 | ts_user = config['TS']['ts_user'] 23 | ts_pass = config['TS']['ts_pass'] 24 | DB_HOST = config['Database']['DB_HOST'] 25 | DB_USER = config['Database']['DB_USER'] 26 | DB_PASS = config['Database']['DB_PASS'] 27 | DB_NAME = config['Database']['DB_NAME'] 28 | 29 | logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) 30 | 31 | logger = logging.getLogger(__name__) 32 | 33 | ADMIN_ID = config.getint('Telegram', 'admin_id') if config.has_option('Telegram', 'admin_id') else None 34 | 35 | 36 | def create_database(): 37 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 38 | try: 39 | with con.cursor() as cur: 40 | cur.execute( 41 | 'SET sql_notes = 0; \ 42 | CREATE TABLE IF NOT EXISTS `TsUsers` ( \ 43 | `Telegram_id` int(11) NOT NULL, \ 44 | `Name` text NOT NULL, \ 45 | `Ts_id` int(11) \ 46 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ 47 | CREATE TABLE IF NOT EXISTS `TsMentions` ( \ 48 | `Group_id` text NOT NULL, \ 49 | `User_id` int(11) NOT NULL \ 50 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ 51 | CREATE TABLE IF NOT EXISTS `Invitations` ( \ 52 | `token` text NOT NULL, \ 53 | `usedBy` int(11) \ 54 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ 55 | SET sql_notes = 1;') 56 | except Exception as exception: 57 | print(str(exception)) 58 | finally: 59 | if con: 60 | con.commit() 61 | con.close() 62 | 63 | 64 | def is_allow(user_id): 65 | allow = False 66 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 67 | try: 68 | with con.cursor() as cur: 69 | cur.execute("SELECT EXISTS(SELECT 1 FROM TsUsers WHERE Telegram_id=%s LIMIT 1)", (str(user_id),)) 70 | allow = bool(cur.fetchone()[0]) 71 | except Exception as exception: 72 | print(str(exception)) 73 | finally: 74 | if con: 75 | con.close() 76 | return allow 77 | 78 | 79 | def get_name(ts_id): 80 | name = None 81 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 82 | try: 83 | with con.cursor() as cur: 84 | cur.execute("SELECT Name FROM TsUsers WHERE Ts_id=%s", (str(ts_id),)) 85 | name = cur.fetchone() 86 | name = name[0] if name is not None else None 87 | 88 | except Exception as exception: 89 | print(str(exception)) 90 | finally: 91 | if con: 92 | con.close() 93 | return name 94 | 95 | 96 | def get_user_ids(): 97 | res = "" 98 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 99 | try: 100 | with con.cursor() as cur: 101 | cur.execute("SELECT Telegram_id FROM TsUsers WHERE Telegram_id != 0") 102 | res = [user_id[0] for user_id in cur.fetchall()] 103 | except Exception as exception: 104 | print(str(exception)) 105 | finally: 106 | if con: 107 | con.close() 108 | return res 109 | 110 | 111 | def ts_connect(): 112 | clients = [] 113 | with ts3.query.TS3Connection(ts_host) as ts3conn: 114 | # Note, that the client will wait for the response and raise a 115 | # **TS3QueryError** if the error id of the response is not 0. 116 | try: 117 | ts3conn.login( 118 | client_login_name=ts_user, 119 | client_login_password=ts_pass 120 | ) 121 | except ts3.query.TS3QueryError as err: 122 | print("Login failed:", err.resp.error["msg"]) 123 | exit(1) 124 | 125 | ts3conn.use(sid=1) 126 | resp = ts3conn.clientlist() 127 | for client in resp.parsed: 128 | db_id = int(client['client_database_id']) 129 | # ID 1 IS SERVERADMIN 130 | if db_id != 1: 131 | name = get_name(db_id) 132 | if name is not None: 133 | clients.append(name) 134 | else: 135 | clients.append(client['client_nickname']) 136 | return clients 137 | 138 | 139 | @user_language 140 | def ts_view(bot, update, message_id=None, chat_id=None): 141 | message = update.message 142 | if is_allow(update.effective_user.id): 143 | res = get_ts_view() 144 | 145 | keyboard = [[InlineKeyboardButton(_("Update"), callback_data='TS_UPDATE')]] 146 | reply_markup = InlineKeyboardMarkup(keyboard) 147 | 148 | if message_id and chat_id: 149 | bot.edit_message_text(text=res, chat_id=chat_id, message_id=message_id, reply_markup=reply_markup, 150 | parse_mode='Markdown') 151 | else: 152 | bot.send_message(message.chat.id, res, reply_to_message_id=message.message_id, reply_markup=reply_markup, 153 | parse_mode='Markdown') 154 | else: 155 | bot.send_message(message.chat.id, _("You aren't allow to use this"), reply_to_message_id=message.message_id) 156 | 157 | 158 | def get_ts_view(): 159 | with ts3.query.TS3Connection(ts_host) as ts3conn: 160 | try: 161 | ts3conn.login( 162 | client_login_name=ts_user, 163 | client_login_password=ts_pass 164 | ) 165 | except ts3.query.TS3QueryError as err: 166 | print("Login failed:", err.resp.error["msg"]) 167 | exit(1) 168 | 169 | channel_tree = ChannelTreeNode.build_tree(ts3conn, sid=1) 170 | res = channel_tree_to_str(channel_tree) 171 | return res 172 | 173 | 174 | def channel_tree_to_str(channel_tree, indent=0): 175 | res = "" 176 | if channel_tree.is_root(): 177 | res += " " * (indent * 3) + "👁‍🗨" + channel_tree.info["virtualserver_name"] 178 | else: 179 | res += "\n" + " " * (indent * 3) + "▫️" + channel_tree.info["channel_name"] 180 | for client in channel_tree.clients: 181 | # Ignore query clients 182 | if client["client_type"] == "1": 183 | continue 184 | alias = get_name(client["client_database_id"]) 185 | nickname = ('*' + client["client_nickname"] + '* (' + get_name(client["client_database_id"]) + ')') \ 186 | if alias is not None else client["client_nickname"] 187 | res += "\n" + " " * (indent * 3 + 3) + "🔘" + nickname + "" 188 | for child in channel_tree.childs: 189 | if len(child.clients) > 0: 190 | res += channel_tree_to_str(child, indent=indent + 1) 191 | return res 192 | 193 | 194 | @user_language 195 | def ts_stats(bot, update): 196 | try: 197 | ts_users = ts_connect() 198 | text = '👁‍🗨 ' + _('Users online:') + '\n' 199 | if len(ts_users) == 0: 200 | text = _('There is no one right now') 201 | else: 202 | for client in ts_users: 203 | text += '%s\n' % client 204 | return text 205 | except Exception as exception: 206 | return exception 207 | 208 | 209 | def get_mention_users_by_group(group_id): 210 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 211 | mention_users = list() 212 | try: 213 | with con.cursor() as cur: 214 | cur.execute("SELECT User_id FROM TsMentions WHERE Group_id = %s", (str(group_id),)) 215 | rows = cur.fetchall() 216 | for row in rows: 217 | mention_users.append(row[0]) 218 | except Exception as exception: 219 | print(exception) 220 | finally: 221 | if con: 222 | con.close() 223 | return mention_users 224 | 225 | 226 | def mention_forwarder(bot, update): 227 | message = update.message 228 | group_id = message.chat_id 229 | 230 | if is_allow(message.from_user.id): 231 | user_ids = get_mention_users_by_group(group_id) 232 | for user_id in user_ids: 233 | try: 234 | bot.forward_message(user_id, group_id, message.message_id) 235 | except: 236 | pass 237 | 238 | 239 | @user_language 240 | def mention_toggle(bot, update, group_id, user_id): 241 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 242 | try: 243 | with con.cursor() as cur: 244 | cur.execute("SELECT EXISTS(SELECT 1 FROM TsMentions WHERE Group_id=%s and User_id=%s LIMIT 1)", 245 | (str(group_id), str(user_id))) 246 | mention = bool(cur.fetchone()[0]) 247 | if not mention: 248 | cur.execute("INSERT INTO TsMentions VALUES (%s, %s)", (str(group_id), str(user_id))) 249 | return '✅ ' + _('Activated mentions') 250 | else: 251 | cur.execute('DELETE FROM TsMentions WHERE Group_id = %s and User_id = %s', (str(group_id), str(user_id))) 252 | return '❎ ' + _('Disabled mentions') 253 | except Exception: 254 | logger.error('Fatal error in mention_toggle', exc_info=True) 255 | finally: 256 | if con: 257 | con.commit() 258 | con.close() 259 | 260 | 261 | def add_user(user_id, name, ts_id=0): 262 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 263 | try: 264 | with con.cursor() as cur: 265 | cur.execute("INSERT INTO TsUsers Values(%s, %s, %s)", (str(user_id), str(name), str(ts_id))) 266 | except Exception: 267 | logger.error('Fatal error in add_user', exc_info=True) 268 | finally: 269 | if con: 270 | con.commit() 271 | con.close() 272 | 273 | 274 | def generate_invitation(): 275 | token = str(uuid.uuid4()) 276 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 277 | try: 278 | with con.cursor() as cur: 279 | cur.execute("INSERT INTO Invitations(token) Values(%s)", (str(token),)) 280 | return token 281 | except Exception: 282 | logger.error('Fatal error in add_user', exc_info=True) 283 | finally: 284 | if con: 285 | con.commit() 286 | con.close() 287 | 288 | 289 | def validate_invitation_token(token, user_id, name): 290 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 291 | try: 292 | with con.cursor() as cur: 293 | cur.execute("SELECT EXISTS(SELECT 1 FROM Invitations WHERE token=%s AND usedBy IS NULL LIMIT 1)", (str(token))) 294 | valid = bool(cur.fetchone()[0]) 295 | if valid: 296 | cur.execute("UPDATE Invitations SET usedBy=%s WHERE token=%s", (str(user_id), str(token))) 297 | cur.execute("INSERT INTO TsUsers Values(%s, %s, 0)", (str(user_id), str(name))) 298 | return True 299 | except Exception: 300 | logger.error('Fatal error in mention_toggle', exc_info=True) 301 | finally: 302 | if con: 303 | con.commit() 304 | con.close() 305 | 306 | 307 | def assign_name_tsid(telegram_id, name, ts_id): 308 | con = pymysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME) 309 | try: 310 | with con.cursor() as cur: 311 | if int(telegram_id) != 0: 312 | cur.execute("UPDATE TsUsers SET Name=%s, Ts_id=%s WHERE Telegram_id=%s", 313 | (str(name), str(ts_id), str(telegram_id))) 314 | cur.execute("DELETE FROM TsUsers WHERE Telegram_id=0 AND Ts_id=%s", (str(ts_id),)) 315 | else: 316 | cur.execute("UPDATE TsUsers SET Name=%s, Telegram_id=%s WHERE Ts_id=%s", 317 | (str(name), str(telegram_id), str(ts_id))) 318 | return True 319 | except Exception: 320 | logger.error('Fatal error in assign_tsid', exc_info=True) 321 | finally: 322 | if con: 323 | con.commit() 324 | con.close() 325 | 326 | 327 | def get_users_tsdb(): 328 | with ts3.query.TS3Connection(ts_host) as ts3conn: 329 | try: 330 | ts3conn.login( 331 | client_login_name=ts_user, 332 | client_login_password=ts_pass 333 | ) 334 | except ts3.query.TS3QueryError as err: 335 | print("Login failed:", err.resp.error["msg"]) 336 | exit(1) 337 | 338 | ts3conn.use(sid=1) 339 | users = ts3conn.clientdblist(duration=100000000*999).parsed 340 | return users 341 | 342 | 343 | def get_ts_groups(include_defaults=False): 344 | with ts3.query.TS3Connection(ts_host) as ts3conn: 345 | try: 346 | ts3conn.login( 347 | client_login_name=ts_user, 348 | client_login_password=ts_pass 349 | ) 350 | except ts3.query.TS3QueryError as err: 351 | print("Login failed:", err.resp.error["msg"]) 352 | exit(1) 353 | 354 | ts3conn.use(sid=1) 355 | ts_groups = ts3conn.servergrouplist().parsed 356 | if not include_defaults: 357 | ts_groups = [ts_group for ts_group in ts_groups if int(ts_group['savedb']) == 1] 358 | return ts_groups 359 | 360 | 361 | def get_ts_groups_by_client_id(cldbid): 362 | with ts3.query.TS3Connection(ts_host) as ts3conn: 363 | try: 364 | ts3conn.login( 365 | client_login_name=ts_user, 366 | client_login_password=ts_pass 367 | ) 368 | except ts3.query.TS3QueryError as err: 369 | print("Login failed:", err.resp.error["msg"]) 370 | exit(1) 371 | 372 | ts3conn.use(sid=1) 373 | ts_groups = ts3conn.servergroupsbyclientid(cldbid=cldbid).parsed 374 | return ts_groups 375 | 376 | 377 | def get_ts_group(group_id): 378 | with ts3.query.TS3Connection(ts_host) as ts3conn: 379 | try: 380 | ts3conn.login( 381 | client_login_name=ts_user, 382 | client_login_password=ts_pass 383 | ) 384 | except ts3.query.TS3QueryError as err: 385 | print("Login failed:", err.resp.error["msg"]) 386 | exit(1) 387 | 388 | ts3conn.use(sid=1) 389 | ts_groups = ts3conn.servergrouplist().parsed 390 | ts_group = next(ts_group for ts_group in ts_groups if ts_group['sgid'] == str(group_id)) 391 | return ts_group 392 | 393 | 394 | def get_ts_users_in_group(group_id): 395 | with ts3.query.TS3Connection(ts_host) as ts3conn: 396 | try: 397 | ts3conn.login( 398 | client_login_name=ts_user, 399 | client_login_password=ts_pass 400 | ) 401 | except ts3.query.TS3QueryError as err: 402 | print("Login failed:", err.resp.error["msg"]) 403 | exit(1) 404 | 405 | ts3conn.use(sid=1) 406 | try: 407 | users = ts3conn.servergroupclientlist(sgid=group_id).parsed 408 | users = [get_user_ts_info(user['cldbid']) for user in users] 409 | return users 410 | except TS3QueryError: 411 | return False 412 | 413 | 414 | def get_user_ts_info(cldbid): 415 | with ts3.query.TS3Connection(ts_host) as ts3conn: 416 | try: 417 | ts3conn.login( 418 | client_login_name=ts_user, 419 | client_login_password=ts_pass 420 | ) 421 | except ts3.query.TS3QueryError as err: 422 | print("Login failed:", err.resp.error["msg"]) 423 | exit(1) 424 | 425 | ts3conn.use(sid=1) 426 | res = ts3conn.clientdbinfo(cldbid=cldbid).parsed[0] 427 | 428 | return res 429 | 430 | 431 | def check_user_banned(uid=None, ip=None, name=None): 432 | with ts3.query.TS3Connection(ts_host) as ts3conn: 433 | try: 434 | ts3conn.login( 435 | client_login_name=ts_user, 436 | client_login_password=ts_pass 437 | ) 438 | except ts3.query.TS3QueryError as err: 439 | print("Login failed:", err.resp.error["msg"]) 440 | exit(1) 441 | 442 | ts3conn.use(sid=1) 443 | banned_users = ts3conn.banlist().parsed 444 | ban_ids = list() 445 | 446 | for user in banned_users: 447 | if user['uid'] == uid or user['ip'] == ip or user['name'] == name: 448 | ban_ids.append(user['banid']) 449 | 450 | return ban_ids 451 | 452 | 453 | def get_user_clid(cluid): 454 | with ts3.query.TS3Connection(ts_host) as ts3conn: 455 | try: 456 | ts3conn.login( 457 | client_login_name=ts_user, 458 | client_login_password=ts_pass 459 | ) 460 | except ts3.query.TS3QueryError as err: 461 | print("Login failed:", err.resp.error["msg"]) 462 | exit(1) 463 | 464 | ts3conn.use(sid=1) 465 | try: 466 | clid = ts3conn.clientgetids(cluid=cluid).parsed[0]['clid'] 467 | return clid 468 | except ts3.query.TS3QueryError: 469 | pass 470 | 471 | 472 | @user_language 473 | def ban_ts_user(bot, update, chat_data, cldbid, ban_type): 474 | user = get_user_ts_info(cldbid) 475 | with ts3.query.TS3Connection(ts_host) as ts3conn: 476 | try: 477 | ts3conn.login( 478 | client_login_name=ts_user, 479 | client_login_password=ts_pass 480 | ) 481 | except ts3.query.TS3QueryError as err: 482 | print("Login failed:", err.resp.error["msg"]) 483 | exit(1) 484 | 485 | ts3conn.use(sid=1) 486 | if ban_type == 'ID': 487 | ts3conn.banadd(uid=user['client_unique_identifier']) 488 | elif ban_type == 'IP': 489 | ts3conn.banadd(ip=user['client_lastip']) 490 | else: 491 | ts3conn.banadd(name=user['client_nickname']) 492 | 493 | bot.answer_callback_query(update.callback_query.id, _('User banned successfully')) 494 | details_user_ts(bot, update, chat_data, cldbid=int(cldbid)) 495 | 496 | 497 | @user_language 498 | def unban_ts_user(bot, update, chat_data, cldbid, banid): 499 | with ts3.query.TS3Connection(ts_host) as ts3conn: 500 | try: 501 | ts3conn.login( 502 | client_login_name=ts_user, 503 | client_login_password=ts_pass 504 | ) 505 | except ts3.query.TS3QueryError as err: 506 | print("Login failed:", err.resp.error["msg"]) 507 | exit(1) 508 | 509 | ts3conn.use(sid=1) 510 | ts3conn.bandel(banid=banid) 511 | 512 | bot.answer_callback_query(update.callback_query.id, _('User unbanned successfully')) 513 | if cldbid: 514 | details_user_ts(bot, update, chat_data, cldbid=cldbid) 515 | else: 516 | send_users_tsdb(bot, update, chat_data) 517 | 518 | 519 | @user_language 520 | def kick_ts_user(bot, update, cldbid, kick_type): 521 | with ts3.query.TS3Connection(ts_host) as ts3conn: 522 | try: 523 | ts3conn.login( 524 | client_login_name=ts_user, 525 | client_login_password=ts_pass 526 | ) 527 | except ts3.query.TS3QueryError as err: 528 | print("Login failed:", err.resp.error["msg"]) 529 | exit(1) 530 | 531 | ts3conn.use(sid=1) 532 | try: 533 | cluid = ts3conn.clientdbinfo(cldbid=cldbid).parsed[0]['client_unique_identifier'] 534 | clid = ts3conn.clientgetids(cluid=cluid).parsed[0]['clid'] 535 | 536 | ts3conn.clientkick(reasonid=kick_type, clid=clid, reasonmsg="Kicked from TeamSpeakBot") 537 | bot.answer_callback_query(update.callback_query.id, _('User kicked successfully')) 538 | except ts3.query.TS3QueryError: 539 | bot.answer_callback_query(update.callback_query.id, _('Something went wrong')) 540 | 541 | 542 | @user_language 543 | def add_ts_user_to_group(bot, update, chat_data, group_id, cldbid): 544 | with ts3.query.TS3Connection(ts_host) as ts3conn: 545 | try: 546 | ts3conn.login( 547 | client_login_name=ts_user, 548 | client_login_password=ts_pass 549 | ) 550 | except ts3.query.TS3QueryError as err: 551 | print("Login failed:", err.resp.error["msg"]) 552 | exit(1) 553 | 554 | ts3conn.use(sid=1) 555 | ts3conn.servergroupaddclient(sgid=group_id, cldbid=cldbid) 556 | 557 | bot.answer_callback_query(update.callback_query.id, _('User added successfully')) 558 | 559 | clean_pages(chat_data, update.effective_message.message_id) 560 | send_ts_group_details(bot, update, chat_data, group_id=group_id) 561 | 562 | 563 | @user_language 564 | def delete_ts_user_to_group(bot, update, chat_data, group_id, cldbid): 565 | with ts3.query.TS3Connection(ts_host) as ts3conn: 566 | try: 567 | ts3conn.login( 568 | client_login_name=ts_user, 569 | client_login_password=ts_pass 570 | ) 571 | except ts3.query.TS3QueryError as err: 572 | print("Login failed:", err.resp.error["msg"]) 573 | exit(1) 574 | 575 | ts3conn.use(sid=1) 576 | ts3conn.servergroupdelclient(sgid=group_id, cldbid=cldbid) 577 | 578 | bot.answer_callback_query(update.callback_query.id, _('User deleted from group successfully')) 579 | 580 | del chat_data[update.effective_message.message_id]['pages'] 581 | send_ts_group_details(bot, update, chat_data, group_id=group_id) 582 | 583 | 584 | @user_language 585 | def markup_append_pagination(bot, update, items, markup, page, callback, items_per_page=10): 586 | pag_max = math.ceil(len(items) / items_per_page) 587 | pag_button = InlineKeyboardButton(_('Page') + ' %s/%s' % (str(page), str(pag_max)), 588 | callback_data='%s_PG_NEXT' % callback) 589 | 590 | if len(items) >= items_per_page: 591 | if page == 1: 592 | sig_button = InlineKeyboardButton(_('Page') + ' %s/%s ⏩' % (str(page), str(pag_max)), 593 | callback_data='%s_PG_NEXT' % callback) 594 | markup.append([sig_button]) 595 | 596 | elif 1 < page < pag_max: 597 | ant_button = InlineKeyboardButton('⏪ ' + _('Prev'), callback_data='%s_PG_PREV' % callback) 598 | sig_button = InlineKeyboardButton('⏩ ' + _('Next'), callback_data='%s_PG_NEXT' % callback) 599 | markup.append([ant_button, pag_button, sig_button]) 600 | elif page == pag_max: 601 | ant_button = InlineKeyboardButton(_('Page') + ' %s/%s ⏪' % (str(page), str(pag_max)), 602 | callback_data='%s_PG_PREV' % callback) 603 | markup.append([ant_button]) 604 | 605 | return markup 606 | 607 | 608 | @user_language 609 | def paginate_items(bot, update, chat_data, items, principal_property, backend_property, text, callback, additional_row=None): 610 | message = update.effective_message 611 | chat_id = message.chat_id 612 | markup = [] 613 | first_message = bool(update.message) 614 | 615 | page = chat_data[message.message_id]['pages'] if not first_message else 1 616 | 617 | start = 10 * (page - 1) if page > 1 else 0 618 | end = start + 10 if start + 10 < len(items) else len(items) 619 | for i in range(start, end, 2): 620 | item1 = items[i] 621 | row = [InlineKeyboardButton(item1[principal_property], 622 | callback_data='%s_DETAIL_%s' % (callback, str(item1[backend_property])))] 623 | if i + 1 < len(items): 624 | item2 = items[i + 1] 625 | row.append(InlineKeyboardButton(item2[principal_property], 626 | callback_data='%s_DETAIL_%s' % (callback, str(item2[backend_property])))) 627 | markup.append(row) 628 | 629 | markup = markup_append_pagination(bot, update, items, markup, page, callback) 630 | 631 | if additional_row is not None: 632 | markup.append(additional_row) 633 | 634 | reply_markup = InlineKeyboardMarkup(markup) 635 | 636 | if len(items) == 0: 637 | text = _('No results') 638 | if not first_message: 639 | bot.edit_message_text(text, chat_id=chat_id, message_id=message.message_id, reply_markup=reply_markup, 640 | parse_mode='Markdown') 641 | else: 642 | msg = bot.send_message(chat_id, text, disable_notification=True, reply_markup=reply_markup, 643 | parse_mode='Markdown') 644 | chat_data[msg.message_id] = dict() 645 | chat_data[msg.message_id]['pages'] = page 646 | 647 | 648 | @user_language 649 | def assign_user_alias_step1(bot, update, chat_data, cldbid): 650 | chat_id = update.effective_chat.id 651 | text = '🙍‍♂️ ' + _('Ok, give me an *alias* for that user') 652 | message_sent = bot.send_message(chat_id, text, reply_markup=ForceReply(), parse_mode='Markdown') 653 | 654 | if 'alias_cldbid' not in chat_data: 655 | chat_data['alias_cldbid'] = dict() 656 | chat_data['alias_cldbid'][str(message_sent.message_id)] = '', cldbid 657 | chat_data['bot_update'] = bot, update 658 | 659 | 660 | @user_language 661 | def assign_user_alias_step2(bot, update, chat_data): 662 | message = update.effective_message 663 | chat_id = update.effective_chat.id 664 | markup = [] 665 | 666 | first_message = bool(update.message) 667 | page = chat_data[message.message_id]['pages'] if not first_message else 1 668 | 669 | user_ids = get_user_ids() 670 | 671 | start = 10 * (page - 1) if page > 1 else 0 672 | end = start + 10 if start + 10 < len(user_ids) else len(user_ids) 673 | for i in range(start, end, 2): 674 | j = i + 1 675 | try: 676 | user1 = bot.get_chat_member(chat_id=user_ids[i], user_id=user_ids[i]).user 677 | username1 = '@' + user1.username if user1.username else user1.first_name 678 | except TelegramError: 679 | username1 = 'ID: ' + str(user_ids[i]) 680 | row = [InlineKeyboardButton(username1, callback_data='USER_ALIAS_%s' % str(user_ids[i]))] 681 | if j < len(user_ids): 682 | try: 683 | user2 = bot.get_chat_member(chat_id=user_ids[j], user_id=user_ids[j]).user 684 | username2 = '@' + user2.username if user2.username else user2.first_name 685 | except TelegramError: 686 | username2 = 'ID: ' + str(user_ids[j]) 687 | row.append(InlineKeyboardButton(username2, callback_data='USER_ALIAS_%s' % str(user_ids[j]))) 688 | markup.append(row) 689 | 690 | markup = markup_append_pagination(bot, update, user_ids, markup, page, 'USER_ALIAS') 691 | markup.append([InlineKeyboardButton('🔜 ' + _('Skip'), callback_data='USER_ALIAS_%s' % str(0))]) 692 | 693 | reply_markup = InlineKeyboardMarkup(markup) 694 | text = '👍 ' + _('Ok, is this user on Telegram?') 695 | 696 | if not first_message: 697 | msg = bot.edit_message_text(text, chat_id=chat_id, message_id=message.message_id, reply_markup=reply_markup, 698 | parse_mode='Markdown') 699 | elif len(user_ids) == 0: 700 | msg = bot.send_message(chat_id, _('No results')) 701 | else: 702 | msg = bot.send_message(chat_id, text, disable_notification=True, reply_markup=reply_markup, 703 | parse_mode='Markdown') 704 | chat_data[msg.message_id] = dict() 705 | chat_data[msg.message_id]['pages'] = page 706 | 707 | if message.reply_to_message: 708 | cldbid = chat_data['alias_cldbid'][str(message.reply_to_message.message_id)][1] 709 | del chat_data['alias_cldbid'][str(message.reply_to_message.message_id)] 710 | bot.delete_message(chat_id=chat_id, message_id=message.reply_to_message.message_id) 711 | chat_data['alias_cldbid'][str(msg.message_id)] = message.text, cldbid 712 | 713 | 714 | @user_language 715 | def assign_user_alias_step3(bot, update, chat_data, telegram_id): 716 | message = update.effective_message 717 | alias, cldbid = chat_data['alias_cldbid'][str(message.message_id)] 718 | 719 | skip = bool(int(telegram_id) == 0) 720 | if skip: 721 | add_user(telegram_id, alias, cldbid) 722 | else: 723 | assign_name_tsid(telegram_id, name=alias, ts_id=cldbid) 724 | 725 | bot.delete_message(chat_id=message.chat_id, message_id=message.message_id) 726 | bot.answer_callback_query(update.callback_query.id, _('Alias assigned successfully'), show_alert=True) 727 | 728 | menu_bot, menu_update = chat_data['bot_update'] 729 | del chat_data['bot_update'] 730 | send_users_tsdb(menu_bot, menu_update, chat_data) 731 | 732 | 733 | @user_language 734 | def send_ts_groups(bot, update, chat_data): 735 | text = '👥 ' + _('*Group list:*') + '\n\n' \ 736 | + _('Here is a list of your TeamSpeak groups, pressing any of them will take you to his detail.') 737 | 738 | paginate_items(bot, update, chat_data, items=get_ts_groups(), principal_property='name', backend_property='sgid', 739 | text=text, callback='GROUP') 740 | 741 | 742 | @user_language 743 | def send_ts_groups_by_user(bot, update, chat_data, cldbid): 744 | text = '👥 ' + _('*Group list:*') + '\n\n' \ 745 | + _('Here is the TeamSpeak group list of this user, pressing any of them will take you to his detail.') 746 | 747 | back_button_row = [InlineKeyboardButton('🔙 ' + _('Back'), callback_data='GROUP_BY_USER_%s_BACK' % cldbid)] 748 | 749 | clean_pages(chat_data, update.effective_message.message_id) 750 | 751 | paginate_items(bot, update, chat_data, items=get_ts_groups_by_client_id(cldbid), 752 | principal_property='name', backend_property='sgid', text=text, callback='GROUP', 753 | additional_row=back_button_row) 754 | 755 | 756 | @user_language 757 | def send_ts_group_details(bot, update, chat_data, group_id=None): 758 | message = update.effective_message 759 | chat_id = message.chat_id 760 | 761 | if group_id is not None: 762 | chat_data[message.message_id]['group_id'] = group_id 763 | else: 764 | group_id = chat_data[message.message_id]['group_id'] 765 | 766 | ts_group = get_ts_group(group_id) 767 | 768 | if int(ts_group['savedb']) == 0: 769 | bot.answer_callback_query(update.callback_query.id, _('Access to default group is forbidden')) 770 | return False 771 | 772 | text = '🔎 *' + ts_group['name'] + ' ' + _('group:') + '*' 773 | markup = [[InlineKeyboardButton('👥 ' + _('List users'), callback_data='GROUP_DETAIL_USERS_%s' % group_id)], 774 | [InlineKeyboardButton('➕ ' + _('Add user'), callback_data='GROUP_%s_ADD' % group_id), 775 | InlineKeyboardButton('➖ ' + _('Delete user'), callback_data='GROUP_%s_DEL' % group_id)], 776 | [InlineKeyboardButton('🔙 ' + _('Back'), callback_data='GROUP_DETAIL_BACK')]] 777 | reply_markup = InlineKeyboardMarkup(markup) 778 | 779 | bot.edit_message_text(text, chat_id=chat_id, message_id=message.message_id, reply_markup=reply_markup, 780 | parse_mode='Markdown') 781 | 782 | 783 | @user_language 784 | def send_ts_users_in_group(bot, update, chat_data, group_id=None): 785 | message = update.effective_message 786 | 787 | text = '👥 ' + _('*Group users:*') + '\n\n' \ 788 | + _('Here is a list of all users in this group, pressing any of them will take you to his detail.') 789 | if group_id is not None: 790 | chat_data[message.message_id]['group_id'] = group_id 791 | else: 792 | group_id = chat_data[message.message_id]['group_id'] 793 | 794 | users = get_ts_users_in_group(group_id) 795 | users = sorted(users, key=lambda user: user['client_lastconnected'], reverse=True) 796 | 797 | back_button_row = [InlineKeyboardButton('🔙 ' + _('Back'), callback_data='GROUP_DETAIL_USERS_%s_BACK' % group_id)] 798 | 799 | paginate_items(bot, update, chat_data, items=users, principal_property='client_nickname', 800 | backend_property='client_database_id', text=text, callback='GROUP_DETAIL_USERS', 801 | additional_row=back_button_row) 802 | 803 | 804 | @user_language 805 | def send_add_user_to_group(bot, update, chat_data, group_id=None): 806 | message = update.effective_message 807 | 808 | text = '👥 ' + _('*Select an user to add to the group:*') 809 | 810 | if group_id is not None: 811 | chat_data[message.message_id]['group_id'] = group_id 812 | else: 813 | group_id = chat_data[message.message_id]['group_id'] 814 | 815 | users = get_users_tsdb() 816 | users = sorted(users, key=lambda user: user['client_lastconnected'], reverse=True) 817 | 818 | back_button_row = [InlineKeyboardButton('🔙 ' + _('Back'), callback_data='GROUP_%s_ADD_BACK' % group_id)] 819 | 820 | paginate_items(bot, update, chat_data, items=users, principal_property='client_nickname', backend_property='cldbid', 821 | text=text, callback='GROUP_%s_ADD' % group_id, additional_row=back_button_row) 822 | 823 | 824 | @user_language 825 | def send_delete_user_from_group(bot, update, chat_data, group_id=None): 826 | message = update.effective_message 827 | 828 | text = '👥 ' + _('*Select an user to delete from group:*') 829 | 830 | if group_id is not None: 831 | chat_data[message.message_id]['group_id'] = group_id 832 | else: 833 | group_id = chat_data[message.message_id]['group_id'] 834 | 835 | users = get_ts_users_in_group(group_id) 836 | users = sorted(users, key=lambda user: user['client_lastconnected'], reverse=True) 837 | 838 | back_button_row = [InlineKeyboardButton('🔙 ' + _('Back'), callback_data='GROUP_%s_DEL_BACK' % group_id)] 839 | 840 | paginate_items(bot, update, chat_data, items=users, principal_property='client_nickname', 841 | backend_property='client_database_id', text=text, callback='GROUP_%s_DEL' % group_id, 842 | additional_row=back_button_row) 843 | 844 | 845 | @user_language 846 | def send_users_tsdb(bot, update, chat_data): 847 | text = '🎙 ' + _('*User list:*') + '\n\n' \ 848 | + _('Here is a list of all your TeamSpeak users, pressing any of them will take you to his detail.') 849 | users = get_users_tsdb() 850 | users = sorted(users, key=lambda user: user['client_lastconnected'], reverse=True) 851 | 852 | paginate_items(bot, update, chat_data, items=users, principal_property='client_nickname', backend_property='cldbid', 853 | text=text, callback='USER') 854 | 855 | 856 | @user_language 857 | def details_user_ts(bot, update, chat_data, cldbid): 858 | message = update.effective_message 859 | chat_id = message.chat_id 860 | user = get_user_ts_info(cldbid) 861 | user_clid = get_user_clid(user['client_unique_identifier']) 862 | markup = list() 863 | 864 | banid = check_user_banned(uid=user['client_unique_identifier']) 865 | text = ('🚫 ' + _('ID banned')) if banid else ('✅ ' + _('ID unbanned')) 866 | action = 'USER_BAN_ID_%s' % cldbid if not banid else 'USER_UNBAN_%s_%s' % (cldbid, banid[0]) 867 | markup_banid = InlineKeyboardButton(text, callback_data=action) 868 | 869 | banid = check_user_banned(ip=user['client_lastip']) 870 | text = ('🚫 ' + _('IP banned')) if banid else ('✅ ' + _('IP unbanned')) 871 | action = 'USER_BAN_IP_%s' % cldbid if not banid else 'USER_UNBAN_%s_%s' % (cldbid, banid[0]) 872 | markup_banip = InlineKeyboardButton(text, callback_data=action) 873 | 874 | markup.append([markup_banid, markup_banip]) 875 | 876 | banid = check_user_banned(name=user['client_nickname']) 877 | text = ('🚫 ' + _('Name banned')) if banid else ('✅ ' + _('Name unbanned')) 878 | action = 'USER_BAN_NAME_%s' % cldbid if not banid else 'USER_UNBAN_%s_%s' % (cldbid, banid[0]) 879 | markup.append([InlineKeyboardButton(text, callback_data=action)]) 880 | 881 | if user_clid: 882 | channel_kick = InlineKeyboardButton(_('Channel kick'), callback_data='USER_KICK_%s_4' % cldbid) 883 | server_kick = InlineKeyboardButton(_('Server kick'), callback_data='USER_KICK_%s_5' % cldbid) 884 | markup.append([channel_kick, server_kick]) 885 | 886 | markup.append([InlineKeyboardButton('🙍‍♂️ ' + _('Assign alias'), callback_data='USER_ALIAS_PRE_%s' % cldbid), 887 | InlineKeyboardButton('👥 ' + _('Groups'), callback_data='GROUP_BY_USER_%s' % cldbid)]) 888 | markup.append([InlineKeyboardButton('🔙 ' + _('Back'), callback_data='USER_BACK')]) 889 | 890 | reply_markup = InlineKeyboardMarkup(markup) 891 | connected = ' 👁‍🗨' if user_clid else '' 892 | last_connection = datetime.fromtimestamp(int(user['client_lastconnected'])).strftime('%d/%m/%Y %H:%M:%S') 893 | last_connection_text = last_connection if connected == '' else _('ONLINE') + ' ' + _('since') + ' ' + last_connection 894 | alias = '\n*Alias:* ' + get_name(cldbid) if get_name(cldbid) is not None else '' 895 | 896 | text = '🔎 ' + _('*User details:*') + '\n' + '\n' + _('*Name:*') + ' ' + user['client_nickname'] + connected \ 897 | + alias \ 898 | + '\n' + _('*Last connection:*') + ' ' + last_connection_text \ 899 | + '\n' + _('*Last IP:*') + ' ' + user['client_lastip'] \ 900 | + '\n' + _('*Client DB identifier:*') + ' ' + str(cldbid) \ 901 | + '\n' + _('*Client Unique identifier:*') + ' ' + user['client_unique_identifier'] \ 902 | + '\n\n' + _('*Date creation:*') + ' ' + \ 903 | datetime.fromtimestamp(int(user['client_created'])).strftime('%d/%m/%Y %H:%M:%S') \ 904 | + '\n' + _('*Total connections:*') + ' ' + user['client_totalconnections'] 905 | 906 | bot.edit_message_text(text, chat_id=chat_id, message_id=message.message_id, reply_markup=reply_markup, 907 | parse_mode='Markdown') 908 | 909 | 910 | def clean_pages(chat_data, message_id): 911 | no_chat_data = message_id not in chat_data or 'pages' not in chat_data[message_id] 912 | if no_chat_data: 913 | chat_data[message_id] = dict() 914 | chat_data[message_id]['pages'] = 1 915 | 916 | 917 | @user_language 918 | def callback_query_handler(bot, update, chat_data): 919 | query_data = update.callback_query.data 920 | message = update.effective_message 921 | 922 | no_chat_data = message.message_id not in chat_data or 'pages' not in chat_data[message.message_id] 923 | 924 | if update.effective_user.id == ADMIN_ID and no_chat_data: 925 | chat_data[message.message_id] = dict() 926 | chat_data[message.message_id]['pages'] = 1 927 | 928 | if query_data.startswith('TS_UPDATE'): 929 | a = get_ts_view() 930 | if a == message.text_markdown: 931 | bot.answer_callback_query(update.callback_query.id, _('No changes')) 932 | else: 933 | ts_view(bot, update, message_id=message.message_id, chat_id=update.effective_chat.id) 934 | bot.answer_callback_query(update.callback_query.id, _('Successfully updated')) 935 | 936 | elif update.effective_user.id != ADMIN_ID: 937 | bot.answer_callback_query(update.callback_query.id, _('You must be admin')) 938 | 939 | elif query_data.startswith('USER'): 940 | if 'PG' in query_data: 941 | chat_data[message.message_id]['pages'] += 1 if 'NEXT' in query_data else -1 942 | send_users_tsdb(bot, update, chat_data) 943 | 944 | elif query_data.startswith('USER_BAN'): 945 | if query_data.startswith('USER_BAN_ID'): 946 | cldbid, ban_type = int(query_data.split('USER_BAN_ID_')[1]), 'ID' 947 | elif query_data.startswith('USER_BAN_IP'): 948 | cldbid, ban_type = int(query_data.split('USER_BAN_IP_')[1]), 'IP' 949 | else: 950 | cldbid, ban_type = int(query_data.split('USER_BAN_NAME_')[1]), 'NAME' 951 | ban_ts_user(bot, update, chat_data, cldbid=cldbid, ban_type=ban_type) 952 | 953 | elif query_data.startswith('USER_UNBAN'): 954 | cldbid, banid = query_data.split("USER_UNBAN_")[1].split("_") 955 | unban_ts_user(bot, update, chat_data, banid=int(banid), cldbid=int(cldbid)) 956 | 957 | elif query_data.startswith('USER_DETAIL'): 958 | cldbid = query_data.split("USER_DETAIL_")[1] 959 | details_user_ts(bot, update, chat_data, cldbid=int(cldbid)) 960 | 961 | elif query_data.startswith('USER_KICK'): 962 | uid, kick_type = query_data.split("USER_KICK_")[1].split("_") 963 | kick_ts_user(bot, update, int(uid), int(kick_type)) 964 | 965 | elif query_data.startswith('USER_ALIAS'): 966 | if query_data.startswith('USER_ALIAS_PRE'): 967 | cldbid = query_data.split("USER_ALIAS_PRE_")[1] 968 | assign_user_alias_step1(bot, update, chat_data, cldbid) 969 | elif query_data.startswith('USER_ALIAS_PG'): 970 | chat_data[message.message_id]['pages'] += 1 if query_data.startswith('USER_ALIAS_PG_NEXT') else -1 971 | assign_user_alias_step2(bot, update, chat_data) 972 | elif query_data.startswith('USER_ALIAS'): 973 | telegram_id = query_data.split("USER_ALIAS_")[1] 974 | assign_user_alias_step3(bot, update, chat_data, telegram_id) 975 | 976 | elif query_data.startswith('USER_BACK'): 977 | send_users_tsdb(bot, update, chat_data) 978 | 979 | elif query_data.startswith('GROUP'): 980 | if 'PG' in query_data: 981 | chat_data[message.message_id]['pages'] += 1 if 'NEXT' in query_data else -1 982 | if query_data.startswith('GROUP_DETAIL_USERS'): 983 | send_ts_users_in_group(bot, update, chat_data) 984 | elif 'ADD' in query_data: 985 | group_id = query_data.split("GROUP_")[1].split("_ADD")[0] 986 | send_add_user_to_group(bot, update, chat_data, group_id=int(group_id)) 987 | elif 'DEL' in query_data: 988 | group_id = query_data.split("GROUP_")[1].split("_DEL")[0] 989 | send_delete_user_from_group(bot, update, chat_data, group_id=int(group_id)) 990 | else: 991 | send_ts_groups(bot, update, chat_data) 992 | 993 | elif query_data.startswith('GROUP_BY_USER'): 994 | cldbid = query_data.split("GROUP_BY_USER_")[1].split("_BACK")[0] 995 | if 'BACK' in query_data: 996 | details_user_ts(bot, update, chat_data, cldbid=int(cldbid)) 997 | else: 998 | send_ts_groups_by_user(bot, update, chat_data, cldbid=cldbid) 999 | 1000 | elif query_data.startswith('GROUP_DETAIL_USERS'): 1001 | if query_data.startswith('GROUP_DETAIL_USERS_DETAIL'): 1002 | cldbid = query_data.split("GROUP_DETAIL_USERS_DETAIL_")[1] 1003 | details_user_ts(bot, update, chat_data, cldbid=int(cldbid)) 1004 | else: 1005 | group_id = query_data.split("GROUP_DETAIL_USERS_")[1].split("_BACK")[0] 1006 | if 'BACK' in query_data: 1007 | send_ts_group_details(bot, update, chat_data, group_id=int(group_id)) 1008 | else: 1009 | send_ts_users_in_group(bot, update, chat_data, group_id=int(group_id)) 1010 | 1011 | elif query_data.startswith('GROUP_DETAIL'): 1012 | if 'BACK' in query_data: 1013 | send_ts_groups(bot, update, chat_data) 1014 | else: 1015 | group_id = query_data.split("GROUP_DETAIL_")[1] 1016 | send_ts_group_details(bot, update, chat_data, group_id=int(group_id)) 1017 | 1018 | elif 'ADD' in query_data: 1019 | if query_data.endswith('ADD') or query_data.endswith('ADD_BACK'): 1020 | group_id = query_data.split("GROUP_")[1].split("_ADD")[0].split("_BACK")[0] 1021 | if 'BACK' in query_data: 1022 | send_ts_group_details(bot, update, chat_data, group_id=int(group_id)) 1023 | else: 1024 | send_add_user_to_group(bot, update, chat_data, group_id=int(group_id)) 1025 | elif 'ADD_DETAIL' in query_data: 1026 | group_id, cldbid = query_data.split("GROUP_")[1].split('_ADD_DETAIL_') 1027 | add_ts_user_to_group(bot, update, chat_data, group_id=int(group_id), cldbid=int(cldbid)) 1028 | 1029 | elif 'DEL' in query_data: 1030 | if query_data.endswith('DEL') or query_data.endswith('DEL_BACK'): 1031 | group_id = query_data.split("GROUP_")[1].split("_DEL")[0].split("_ADD")[0].split("_BACK")[0] 1032 | if 'BACK' in query_data: 1033 | send_ts_group_details(bot, update, chat_data, group_id=int(group_id)) 1034 | else: 1035 | send_delete_user_from_group(bot, update, chat_data, group_id=int(group_id)) 1036 | elif 'DEL_DETAIL' in query_data: 1037 | group_id, cldbid = query_data.split("GROUP_")[1].split('_DEL_DETAIL_') 1038 | delete_ts_user_to_group(bot, update, chat_data, group_id=int(group_id), cldbid=int(cldbid)) 1039 | 1040 | 1041 | def ts_gm(message_text): 1042 | with ts3.query.TS3Connection(ts_host) as ts3conn: 1043 | try: 1044 | ts3conn.login( 1045 | client_login_name=ts_user, 1046 | client_login_password=ts_pass 1047 | ) 1048 | except ts3.query.TS3QueryError as err: 1049 | print("Login failed:", err.resp.error["msg"]) 1050 | exit(1) 1051 | 1052 | ts3conn.use(sid=1) 1053 | ts3conn.gm(msg=message_text) 1054 | 1055 | 1056 | @user_language 1057 | def pre_send_gm(bot, update): 1058 | message = update.message 1059 | if is_allow(message.from_user.id): 1060 | text = _("Ok, what message do you want to send?\nUse /cancel to cancel the command.") 1061 | bot.send_message(message.chat_id, text, reply_to_message_id=message.message_id, 1062 | reply_markup=ForceReply(selective=True)) 1063 | return 0 1064 | else: 1065 | text = _("You aren't allow to use this") 1066 | bot.send_message(message.chat_id, text, reply_to_message_id=message.message_id) 1067 | return ConversationHandler.END 1068 | 1069 | 1070 | @user_language 1071 | def send_gm(bot, update): 1072 | message = update.message 1073 | ts_gm(message.text) 1074 | 1075 | text = _("Global message has been sent to server successfully.") 1076 | bot.send_message(message.chat_id, text, reply_to_message_id=message.message_id) 1077 | return ConversationHandler.END 1078 | --------------------------------------------------------------------------------