├── requirements.txt ├── config.json ├── _bot.py ├── utils ├── password_generator.py ├── set_root_password_script.py ├── localizer.py └── db.py ├── main.py ├── modules ├── __init__.py ├── delete_account.py ├── manage_droplets.py ├── manage_accounts.py ├── batch_test_delete_accounts.py ├── start.py ├── account_detail.py ├── batch_test_accounts.py ├── add_account.py ├── list_droplets.py ├── droplet_detail.py ├── droplet_actions.py └── create_droplet.py ├── README.MD ├── bot.py └── start /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FighterTunnel/DigitalOcean-TeleBot/HEAD/requirements.txt -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "BOT": { 3 | "NAME": "NAMA STORE", 4 | "TOKEN": "BOT TOKEN", 5 | "ADMINS": [ID TELEGRAM 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /_bot.py: -------------------------------------------------------------------------------- 1 | from os import environ 2 | 3 | import telebot 4 | 5 | bot_token = environ.get('bot_token') 6 | 7 | bot = telebot.TeleBot(token=bot_token) 8 | -------------------------------------------------------------------------------- /utils/password_generator.py: -------------------------------------------------------------------------------- 1 | from random import choice 2 | 3 | 4 | def password_generator(): 5 | a = 'QWERTYUIOPASDFGHJKLZXCVBNM' 6 | b = 'qwertyuiopasdfghjklzxcvbnm' 7 | c = '1234567890' 8 | 9 | p = '' 10 | for i in range(3): 11 | p += choice(a) 12 | p += choice(b) 13 | p += choice(c) 14 | 15 | return p 16 | -------------------------------------------------------------------------------- /utils/set_root_password_script.py: -------------------------------------------------------------------------------- 1 | def set_root_password_script(password: str): 2 | return '#!/bin/bash\n' \ 3 | f'echo root:{password} | sudo chpasswd root\n' \ 4 | 'sudo sed -i "s/^.*PermitRootLogin.*/PermitRootLogin yes/g" /etc/ssh/sshd_config\n' \ 5 | 'sudo sed -i "s/^.*PasswordAuthentication.*/PasswordAuthentication yes/g" /etc/ssh/sshd_config\n' \ 6 | 'sudo systemctl restart sshd\n' 7 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | def parse_config(): 2 | import json 3 | from os import environ 4 | 5 | config = json.load(open('config.json', 'r', encoding='utf-8')) 6 | environ['bot_name'] = config['BOT']['NAME'] 7 | environ['bot_token'] = config['BOT']['TOKEN'] 8 | environ['bot_admins'] = json.dumps(config['BOT']['ADMINS']) 9 | 10 | 11 | def start_bot(): 12 | from bot import bot 13 | 14 | bot.polling(none_stop=True) 15 | 16 | 17 | if __name__ == '__main__': 18 | parse_config() 19 | start_bot() 20 | -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- 1 | from .start import start 2 | from .add_account import add_account 3 | from .manage_accounts import manage_accounts 4 | from .batch_test_accounts import batch_test_accounts 5 | from .account_detail import account_detail 6 | from .manage_droplets import manage_droplets 7 | from .delete_account import delete_account 8 | from .batch_test_delete_accounts import batch_test_delete_accounts 9 | from .create_droplet import create_droplet 10 | from .list_droplets import list_droplets 11 | from .droplet_detail import droplet_detail 12 | from .droplet_actions import droplet_actions 13 | -------------------------------------------------------------------------------- /utils/localizer.py: -------------------------------------------------------------------------------- 1 | def localize_region(slug: str): 2 | regions = [ 3 | {'slug': 'nyc1', 'name': 'New York 1'}, {'slug': 'nyc2', 'name': 'New York 2'}, {'slug': 'nyc3', 'name': 'New York 3'}, 4 | {'slug': 'sfo1', 'name': 'San Fransisco 1'}, {'slug': 'sfo2', 'name': 'San Fransisco 2'}, {'slug': 'sfo3', 'name': 'San Fransisco 3'}, 5 | {'slug': 'ams2', 'name': 'Amsterdam 2'}, {'slug': 'ams3', 'name': 'Amsterdam 3'}, 6 | {'slug': 'sgp1', 'name': 'Singapura 1'}, {'slug': 'lon1', 'name': 'London 1'}, 7 | {'slug': 'fra1', 'name': 'Perancis 1'}, {'slug': 'blr1', 'name': 'Bandolore 1'}, 8 | {'slug': 'tor1', 'name': 'Toronto 1'}, 9 | ] 10 | 11 | for region in regions: 12 | if region['slug'] == slug: 13 | return region['name'] 14 | 15 | return slug 16 | -------------------------------------------------------------------------------- /modules/delete_account.py: -------------------------------------------------------------------------------- 1 | from telebot.types import CallbackQuery 2 | 3 | from _bot import bot 4 | from utils.db import AccountsDB 5 | 6 | 7 | def delete_account(call: CallbackQuery, data: dict): 8 | doc_id = data['doc_id'][0] 9 | 10 | try: 11 | AccountsDB().remove(doc_id=doc_id) 12 | except Exception as e: 13 | bot.edit_message_text( 14 | text=f'{call.message.html_text}\n\n' 15 | f'⚠️ Terjadi kesalahan saat menghapus akun: {str(e)}', 16 | chat_id=call.from_user.id, 17 | message_id=call.message.message_id, 18 | parse_mode='HTML' 19 | ) 20 | return 21 | 22 | bot.edit_message_text( 23 | text=f'{call.message.html_text}\n\n' 24 | f'✅ Akun berhasil dihapus', 25 | chat_id=call.from_user.id, 26 | message_id=call.message.message_id, 27 | parse_mode='HTML' 28 | ) 29 | -------------------------------------------------------------------------------- /utils/db.py: -------------------------------------------------------------------------------- 1 | from tinydb import TinyDB, where 2 | from datetime import datetime 3 | 4 | db_file = 'db.json' 5 | 6 | 7 | class AccountsDB: 8 | 9 | def __init__(self): 10 | db = TinyDB(db_file) 11 | self.accounts = db.table('Accounts') 12 | 13 | def save(self, email: str, token: str, remarks: str = ''): 14 | email = email.strip() 15 | token = token.strip() 16 | date = datetime.today().strftime('%Y-%m-%d') 17 | 18 | if self.accounts.get(where('token') == token): 19 | raise Exception('Token Exists') 20 | else: 21 | self.accounts.insert({ 22 | 'email': email, 23 | 'token': token, 24 | 'remarks': remarks, 25 | 'date': date 26 | }) 27 | 28 | def all(self): 29 | return self.accounts.all() 30 | 31 | def get(self, doc_id: int): 32 | return self.accounts.get(doc_id=int(doc_id)) 33 | 34 | def remove(self, doc_id: int): 35 | self.accounts.remove(doc_ids=[int(doc_id)]) 36 | -------------------------------------------------------------------------------- /modules/manage_droplets.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from telebot.types import ( 4 | Message, 5 | CallbackQuery, 6 | InlineKeyboardMarkup, 7 | InlineKeyboardButton, 8 | ) 9 | 10 | from _bot import bot 11 | from utils.db import AccountsDB 12 | 13 | 14 | def manage_droplets(d: Union[Message, CallbackQuery]): 15 | t = 'Manajer VPS\n\n' 16 | markup = InlineKeyboardMarkup() 17 | 18 | accounts = AccountsDB().all() 19 | 20 | if len(accounts) == 0: 21 | markup.row( 22 | InlineKeyboardButton( 23 | text='➕ Tambah Akun', 24 | callback_data='add_account' 25 | ) 26 | ) 27 | 28 | bot.send_message( 29 | text=f'{t}' 30 | f'⚠️ Tidak ada akun yang tersedia', 31 | chat_id=d.from_user.id, 32 | reply_markup=markup, 33 | parse_mode='HTML' 34 | ) 35 | return 36 | 37 | for account in accounts: 38 | markup.add( 39 | InlineKeyboardButton( 40 | text=f'📧 {account["email"]}', 41 | callback_data=f'list_droplets?doc_id={account.doc_id}' 42 | ) 43 | ) 44 | 45 | bot.send_message( 46 | text=f'{t}' 47 | f'🔢 Pilih akun yang ingin dikelola', 48 | chat_id=d.from_user.id, 49 | parse_mode='HTML', 50 | reply_markup=markup 51 | ) 52 | -------------------------------------------------------------------------------- /modules/manage_accounts.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from telebot.types import ( 4 | Message, 5 | CallbackQuery, 6 | InlineKeyboardMarkup, 7 | InlineKeyboardButton, 8 | ) 9 | 10 | from _bot import bot 11 | from utils.db import AccountsDB 12 | 13 | 14 | def manage_accounts(d: Union[Message, CallbackQuery]): 15 | t = 'Manajer Akun\n\n' 16 | markup = InlineKeyboardMarkup() 17 | 18 | accounts = AccountsDB().all() 19 | 20 | if len(accounts) == 0: 21 | t += '⚠️ Tidak ada akun yang tersedia' 22 | markup.row( 23 | InlineKeyboardButton( 24 | text='➕ Tambahkan Akun Baru', 25 | callback_data='add_account' 26 | ) 27 | ) 28 | 29 | bot.send_message( 30 | text=t, 31 | chat_id=d.from_user.id, 32 | reply_markup=markup, 33 | parse_mode='HTML' 34 | ) 35 | return 36 | 37 | markup.row( 38 | InlineKeyboardButton( 39 | text='🛠️ Uji Batch Akun', 40 | callback_data='batch_test_accounts' 41 | ) 42 | ) 43 | 44 | for account in accounts: 45 | markup.row( 46 | InlineKeyboardButton( 47 | text=f'📧 {account.get("email", "error")}', 48 | callback_data=f'account_detail?doc_id={account.doc_id}' 49 | ) 50 | ) 51 | 52 | bot.send_message( 53 | text=t, 54 | chat_id=d.from_user.id, 55 | reply_markup=markup, 56 | parse_mode='HTML' 57 | ) 58 | -------------------------------------------------------------------------------- /modules/batch_test_delete_accounts.py: -------------------------------------------------------------------------------- 1 | from telebot.types import CallbackQuery 2 | 3 | import digitalocean 4 | from digitalocean import DataReadError 5 | 6 | from _bot import bot 7 | from utils.db import AccountsDB 8 | 9 | 10 | def batch_test_delete_accounts(call: CallbackQuery): 11 | bot.edit_message_text( 12 | text=f'{call.message.html_text}\n\n' 13 | f'🔄 Menghapus Akun Gagal...', 14 | chat_id=call.from_user.id, 15 | message_id=call.message.message_id, 16 | parse_mode='HTML' 17 | ) 18 | 19 | accounts_db = AccountsDB() 20 | 21 | accounts = accounts_db.all() 22 | for account in accounts: 23 | try: 24 | digitalocean.Balance().get_object(api_token=account['token']) 25 | except DataReadError: 26 | try: 27 | accounts_db.remove(doc_id=account.doc_id) 28 | except Exception as e: 29 | bot.edit_message_text( 30 | text=f'{call.message.html_text}\n\n' 31 | f'⚠️ Kesalahan saat menghapus akun: {str(e)}', 32 | chat_id=call.from_user.id, 33 | message_id=call.message.message_id, 34 | parse_mode='HTML' 35 | ) 36 | return 37 | 38 | bot.edit_message_text( 39 | text=f'{call.message.html_text}\n\n' 40 | f'✅ Akun gagal telah dihapus', 41 | chat_id=call.from_user.id, 42 | message_id=call.message.message_id, 43 | parse_mode='HTML' 44 | ) 45 | -------------------------------------------------------------------------------- /modules/start.py: -------------------------------------------------------------------------------- 1 | from os import environ 2 | 3 | from telebot.types import ( 4 | Message, 5 | InlineKeyboardMarkup, 6 | InlineKeyboardButton, 7 | ) 8 | 9 | from _bot import bot 10 | 11 | bot_name = environ.get('bot_name', 'Asisten DigitalOcean') 12 | 13 | 14 | def start(d: Message): 15 | markup = InlineKeyboardMarkup(row_width=2) 16 | markup.add( 17 | InlineKeyboardButton( 18 | text='➕ Tambah akun', 19 | callback_data='add_account' 20 | ), 21 | InlineKeyboardButton( 22 | text='⚙️ Kelola akun', 23 | callback_data='manage_accounts' 24 | ), 25 | InlineKeyboardButton( 26 | text='💧 Buat droplets', 27 | callback_data='create_droplet' 28 | ), 29 | InlineKeyboardButton( 30 | text='🛠️ Kelola droplets', 31 | callback_data='manage_droplets' 32 | ), 33 | ) 34 | t = f'Selamat Datang {bot_name} 👋\n\n' \ 35 | 'Anda dapat mengelola akun DigitalOcean, membuat instance, dll.\n\n' \ 36 | 'Perintah cepat:\n' \ 37 | '/start - Memulai bot\n' \ 38 | '/add_do - Tambah akun\n' \ 39 | '/sett_do - Kelola akun\n' \ 40 | '/bath_do - Uji batch akun\n' \ 41 | '/add_vps - Buat droplets\n' \ 42 | '/sett_vps - Kelola droplets\n' \ 43 | ' \n' \ 44 | 'Dev: @yha_bot 👨‍💻\n' \ 45 | 'Support: @fightertunnell 🛡️' 46 | bot.send_message( 47 | text=t, 48 | chat_id=d.from_user.id, 49 | parse_mode='HTML', 50 | reply_markup=markup 51 | ) 52 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # ☁ `Digitalocean-bot` 2 | 3 | ![](.README.MD_images/1be8fb97.png) 4 | 5 | ### 🚚 Telegram Bot untuk Digital Ocean 6 | 7 | ### 🔖 Fungsi Utama 8 | 9 | + Mengelola akun Digital Ocean, memeriksa saldo akun, dan melakukan pengujian akun dalam batch dengan cepat dan akurat. 10 | + Membuat dan mengelola mesin virtual dengan mudah dan efisien, memberikan Anda kendali penuh atas infrastruktur cloud Anda. 11 | 12 | ### 🪂 Lingkungan 13 | 14 | + Bot ini dirancang untuk bekerja di berbagai lingkungan, memastikan fleksibilitas dan kompatibilitas yang tinggi. 15 | 16 | ### 😻 Tahapan Penggunaan 17 | 18 | 1. **Clone Proyek**: `git clone` proyek ini ke lokal untuk memulai petualangan Anda. 19 | 2. **Instal Ketergantungan**: Jalankan `pip3 install -r requirements.txt` untuk menginstal ketergantungan yang diperlukan dan pastikan semuanya siap. 20 | 3. **Buat Bot**: Buat bot baru melalui [@botfather](https://t.me/botfather) dan catat `token` yang diberikan untuk menghubungkan bot Anda. 21 | 4. **Edit Konfigurasi**: Edit file `config.json` untuk mengisi konfigurasi yang relevan dengan akun Anda dan sesuaikan dengan kebutuhan Anda. 22 | 5. **Jalankan Bot**: Jalankan `python3 main.py` untuk memulai bot dan nikmati kemudahan pengelolaan Digital Ocean Anda dengan antarmuka yang ramah pengguna! 23 | 24 | ### 🤖 Identitas Bot 25 | 26 | + **Nama Bot**: DigitalOcean Manager Bot 27 | + **Deskripsi**: Bot ini membantu Anda mengelola akun DigitalOcean, memeriksa saldo, membuat dan mengelola droplet, serta memberikan informasi detail tentang akun dan droplet Anda. 28 | + **Versi**: 1.0.0 29 | + **Bahasa Pemrograman**: Python 30 | + **Perpustakaan Utama**: `pyTelegramBotAPI`, `digitalocean` 31 | + **Lisensi**: MIT License 32 | -------------------------------------------------------------------------------- /modules/account_detail.py: -------------------------------------------------------------------------------- 1 | from telebot.types import ( 2 | CallbackQuery, 3 | InlineKeyboardMarkup, 4 | InlineKeyboardButton, 5 | ) 6 | 7 | import digitalocean 8 | from digitalocean import DataReadError 9 | 10 | from _bot import bot 11 | from utils.db import AccountsDB 12 | 13 | 14 | def account_detail(call: CallbackQuery, data: dict): 15 | doc_id = data['doc_id'][0] 16 | t = 'ℹ️ Informasi Akun\n\n' 17 | 18 | account = AccountsDB().get(doc_id=doc_id) 19 | 20 | msg = bot.send_message( 21 | text=f'{t}' 22 | f'📧 Email: {account["email"]}\n\n' 23 | f'🔄 Mendapatkan informasi...', 24 | chat_id=call.from_user.id, 25 | parse_mode='HTML' 26 | ) 27 | 28 | t += f'📧 Email: {account["email"]}\n' \ 29 | f'💬 Komentar: {account["remarks"]}\n' \ 30 | f'📅 Tanggal Ditambahkan: {account["date"]}\n' \ 31 | f'🔑 Token: {account["token"]}\n\n' 32 | markup = InlineKeyboardMarkup() 33 | markup.row( 34 | InlineKeyboardButton( 35 | text='🗑️ Hapus Akun', 36 | callback_data=f'delete_account?doc_id={account.doc_id}' 37 | ) 38 | ) 39 | 40 | try: 41 | account_balance = digitalocean.Balance().get_object(api_token=account['token']) 42 | 43 | t += f'💰 Saldo Akun: {account_balance.account_balance}\n' \ 44 | f'📊 Penggunaan Bulan Ini: {account_balance.month_to_date_usage}\n' \ 45 | f'📅 Tanggal Penagihan: {account_balance.generated_at.split("T")[0]}' 46 | 47 | except DataReadError as e: 48 | t += f'⚠️ Kesalahan Mendapatkan Tagihan: {e}' 49 | except Exception as e: 50 | t += f'⚠️ Kesalahan: {e}' 51 | 52 | bot.edit_message_text( 53 | text=t, 54 | chat_id=call.from_user.id, 55 | message_id=msg.message_id, 56 | parse_mode='HTML', 57 | reply_markup=markup 58 | ) 59 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | import traceback 4 | from os import environ 5 | from typing import Union 6 | import urllib.parse as urlparse 7 | from urllib.parse import parse_qs 8 | 9 | import telebot 10 | from telebot.types import CallbackQuery, Message 11 | 12 | from _bot import bot 13 | # noinspection PyUnresolvedReferences 14 | from modules import * 15 | 16 | bot_admins = json.loads(environ.get('bot_admins')) 17 | 18 | logger = telebot.logger 19 | telebot.logger.setLevel(logging.INFO) 20 | 21 | command_dict = { 22 | '/start': 'start', 23 | 24 | '/add_do': 'add_account', 25 | '/sett_do': 'manage_accounts', 26 | '/bath_do': 'batch_test_accounts', 27 | 28 | '/add_vps': 'create_droplet', 29 | '/sett_vps': 'manage_droplets', 30 | } 31 | 32 | 33 | @bot.message_handler(content_types=['text']) 34 | def text_handler(m: Message): 35 | try: 36 | logger.info(m) 37 | 38 | if m.from_user.id not in bot_admins: 39 | bot.send_message( 40 | text='🚫 Anda tidak memiliki izin untuk menggunakan bot ini.', 41 | chat_id=m.from_user.id 42 | ) 43 | return 44 | 45 | if m.text in command_dict.keys(): 46 | globals()[command_dict[m.text]](m) 47 | 48 | except Exception as e: 49 | traceback.print_exc() 50 | handle_exception(m, e) 51 | 52 | 53 | @bot.callback_query_handler(func=lambda call: True) 54 | def callback_query_handler(call: CallbackQuery): 55 | try: 56 | logger.info(call) 57 | 58 | if call.from_user.id not in bot_admins: 59 | bot.send_message( 60 | text='🚫 Anda tidak memiliki izin untuk menggunakan bot ini.', 61 | chat_id=call.from_user.id 62 | ) 63 | return 64 | 65 | callback_data = urlparse.urlparse(call.data) 66 | func_name = callback_data.path 67 | data = parse_qs(callback_data.query) 68 | if func_name in globals(): 69 | args = [call] 70 | if len(data.keys()) > 0: 71 | args.append(data) 72 | 73 | globals()[func_name](*args) 74 | 75 | except Exception as e: 76 | traceback.print_exc() 77 | handle_exception(call, e) 78 | 79 | 80 | def handle_exception(d: Union[Message, CallbackQuery], e): 81 | bot.send_message( 82 | text=f'❌ Terjadi kesalahan\n' 83 | f'{e}', 84 | chat_id=d.from_user.id, 85 | parse_mode='HTML' 86 | ) 87 | -------------------------------------------------------------------------------- /modules/batch_test_accounts.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Union 3 | 4 | from telebot.types import ( 5 | Message, 6 | CallbackQuery, 7 | InlineKeyboardMarkup, 8 | InlineKeyboardButton, 9 | ) 10 | 11 | import digitalocean 12 | from digitalocean import DataReadError 13 | 14 | from _bot import bot 15 | from utils.db import AccountsDB 16 | 17 | 18 | def batch_test_accounts(d: Union[Message, CallbackQuery]): 19 | t = '🔍 Akun Tes Batch\n\n' 20 | markup = InlineKeyboardMarkup() 21 | 22 | msg = bot.send_message( 23 | text=f'{t}' 24 | f'🔄 Sedang Menguji...', 25 | chat_id=d.from_user.id, 26 | parse_mode='HTML', 27 | ) 28 | 29 | accounts = AccountsDB().all() 30 | checked_accounts = [] 31 | failed_accounts = [] 32 | 33 | for account in accounts: 34 | try: 35 | account_balance = digitalocean.Balance().get_object(api_token=account['token']) 36 | account_balance.email = account['email'] 37 | 38 | checked_accounts.append(account_balance) 39 | 40 | except DataReadError: 41 | failed_accounts.append(account['email']) 42 | except Exception as e: 43 | bot.edit_message_text( 44 | text=f'{t}' 45 | f'⚠️ Kesalahan saat memeriksa akun: {str(e)}', 46 | chat_id=d.from_user.id, 47 | message_id=msg.message_id, 48 | parse_mode='HTML' 49 | ) 50 | return 51 | 52 | t += f'Total {len(accounts)} Akun\n\n' 53 | 54 | if checked_accounts: 55 | t += f'✅ Tes Berhasil {len(checked_accounts)} akun:\n' 56 | for account_balance in checked_accounts: 57 | t += f'{account_balance.email} | Saldo: {account_balance.account_balance}\n' 58 | t += '\n' 59 | 60 | if failed_accounts: 61 | t += f'❌ Tes Gagal {len(failed_accounts)} akun:\n' 62 | for email in failed_accounts: 63 | t += f'{email}\n' 64 | markup.add( 65 | InlineKeyboardButton( 66 | text='🗑️ Hapus Akun Gagal', 67 | callback_data=json.dumps({ 68 | 't': 'batch_test_delete_accounts' 69 | }) 70 | ) 71 | ) 72 | 73 | bot.edit_message_text( 74 | text=t, 75 | chat_id=d.from_user.id, 76 | message_id=msg.message_id, 77 | parse_mode='HTML', 78 | reply_markup=markup 79 | ) 80 | -------------------------------------------------------------------------------- /start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | while true; do 3 | read -p "Masukkan bot token: " bot_token 4 | if [[ -n "$bot_token" ]]; then 5 | break 6 | else 7 | echo "Bot token tidak boleh kosong. Silakan coba lagi." 8 | fi 9 | done 10 | 11 | while true; do 12 | read -p "Masukkan bot admin ID: " bot_admin_id 13 | if [[ "$bot_admin_id" =~ ^[0-9]+$ ]]; then 14 | break 15 | else 16 | echo "Bot admin ID harus berupa angka. Silakan coba lagi." 17 | fi 18 | done 19 | 20 | while true; do 21 | read -p "Masukkan nama store: " nama_store 22 | if [[ -n "$nama_store" ]]; then 23 | break 24 | else 25 | echo "Nama store tidak boleh kosong. Silakan coba lagi." 26 | fi 27 | done 28 | 29 | apt update -y 30 | 31 | if ! command -v python3 &> /dev/null 32 | then 33 | apt install python3 -y 34 | else 35 | echo "python3 sudah terinstal" 36 | fi 37 | 38 | if ! command -v pip3 &> /dev/null 39 | then 40 | apt install python3-pip -y 41 | else 42 | echo "pip3 sudah terinstal" 43 | fi 44 | 45 | if [ ! -d "/root/DigitalOcean-TeleBot" ]; then 46 | git clone https://github.com/FighterTunnel/DigitalOcean-TeleBot.git 47 | else 48 | echo "Repository sudah ada" 49 | fi 50 | 51 | if [ -f "/root/DigitalOcean-TeleBot/requirements.txt" ]; then 52 | pip3 install -r /root/DigitalOcean-TeleBot/requirements.txt 53 | else 54 | echo "File requirements.txt tidak ditemukan" 55 | fi 56 | 57 | 58 | SERVICE_NAME="do" 59 | SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME.service" 60 | if [ -f "/root/DigitalOcean-TeleBot/config.json" ]; then 61 | rm /root/DigitalOcean-TeleBot/config.json 62 | fi 63 | 64 | cat < /root/DigitalOcean-TeleBot/config.json 65 | { 66 | "BOT": { 67 | "NAME": "$nama_store", 68 | "TOKEN": "$bot_token", 69 | "ADMINS": [$bot_admin_id] 70 | } 71 | } 72 | EOT 73 | if [ ! -f "$SERVICE_FILE" ]; then 74 | echo "[Unit] 75 | Description=My Python Service 76 | After=network.target 77 | 78 | [Service] 79 | ExecStart=/usr/bin/python3 /root/DigitalOcean-TeleBot/main.py 80 | WorkingDirectory=/root/DigitalOcean-TeleBot 81 | StandardOutput=inherit 82 | StandardError=inherit 83 | Restart=always 84 | User=root 85 | 86 | [Install] 87 | WantedBy=multi-user.target" > $SERVICE_FILE 88 | 89 | 90 | systemctl daemon-reload 91 | 92 | 93 | systemctl enable $SERVICE_NAME 94 | 95 | 96 | systemctl start $SERVICE_NAME 97 | 98 | 99 | systemctl restart $SERVICE_NAME 100 | else 101 | echo "Service $SERVICE_NAME sudah ada" 102 | fi 103 | 104 | echo "Service $SERVICE_NAME telah diinstal" 105 | -------------------------------------------------------------------------------- /modules/add_account.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from telebot.types import ( 4 | Message, 5 | CallbackQuery 6 | ) 7 | 8 | import digitalocean 9 | from digitalocean import DataReadError 10 | 11 | from _bot import bot 12 | from utils.db import AccountsDB 13 | from .start import start 14 | 15 | 16 | def add_account(d: Union[Message, CallbackQuery]): 17 | t = '🔑 Tambahkan Akun DigitalOcean\n\n' \ 18 | 'Masukkan Token DigitalOcean Ambil Disini perhatikan dalam copy paste\n\n' \ 19 | 'Contoh:\n' \ 20 | 'token123:Komentarxxx\n' \ 21 | 'token345\n\n' \ 22 | '/cancel untuk membatalkan' 23 | 24 | msg = bot.send_message( 25 | text=t, 26 | chat_id=d.from_user.id, 27 | parse_mode='HTML', 28 | disable_web_page_preview=True 29 | ) 30 | 31 | bot.register_next_step_handler(msg, add_account_next_step_handler) 32 | 33 | 34 | def add_account_next_step_handler(m: Message): 35 | if m.text == '/cancel': 36 | start(m) 37 | return 38 | 39 | msg = bot.send_message( 40 | text='🔄 Menambahkan akun...', 41 | chat_id=m.from_user.id 42 | ) 43 | 44 | accounts = m.text.split('\n') 45 | added_accounts = [] 46 | failed_accounts = [] 47 | 48 | for account in accounts: 49 | if ':' in account: 50 | token = account.split(':')[0] 51 | remarks = account.split(':')[1] 52 | else: 53 | token = account 54 | remarks = '' 55 | 56 | try: 57 | email = digitalocean.Account().get_object( 58 | api_token=token 59 | ).email 60 | 61 | AccountsDB().save( 62 | email=email, 63 | token=token, 64 | remarks=remarks 65 | ) 66 | 67 | added_accounts.append(email) 68 | 69 | except DataReadError: 70 | failed_accounts.append(account) 71 | except Exception as e: 72 | bot.edit_message_text( 73 | text=f'⚠️ Kesalahan saat menambahkan akun: {str(e)}', 74 | chat_id=m.from_user.id, 75 | message_id=msg.message_id, 76 | parse_mode='HTML' 77 | ) 78 | return 79 | 80 | t = f'📊 Total {len(accounts)} akun\n\n' 81 | 82 | if added_accounts: 83 | t += f'✅ Berhasil menambahkan {len(added_accounts)} akun:\n' 84 | for added_account in added_accounts: 85 | t += f'{added_account}\n' 86 | t += '\n' 87 | 88 | if failed_accounts: 89 | t += f'❌ Gagal menambahkan {len(failed_accounts)} akun:\n' 90 | for failed_account in failed_accounts: 91 | t += f'{failed_account}\n' 92 | 93 | bot.edit_message_text( 94 | text=t, 95 | chat_id=m.from_user.id, 96 | message_id=msg.message_id, 97 | parse_mode='HTML' 98 | ) 99 | -------------------------------------------------------------------------------- /modules/list_droplets.py: -------------------------------------------------------------------------------- 1 | from telebot.types import ( 2 | CallbackQuery, 3 | InlineKeyboardMarkup, 4 | InlineKeyboardButton, 5 | ) 6 | 7 | import digitalocean 8 | 9 | from _bot import bot 10 | from utils.db import AccountsDB 11 | from utils.localizer import localize_region 12 | 13 | 14 | def list_droplets(call: CallbackQuery, data: dict): 15 | doc_id = data['doc_id'][0] 16 | t = '🔧 VPS Manager\n\n' 17 | 18 | try: 19 | account = AccountsDB().get(doc_id=doc_id) 20 | except Exception as e: 21 | bot.edit_message_text( 22 | text=f'{t}' 23 | '⚠️ Kesalahan saat mengambil akun: ' 24 | f'{str(e)}', 25 | chat_id=call.from_user.id, 26 | message_id=call.message.message_id, 27 | parse_mode='HTML' 28 | ) 29 | return 30 | 31 | bot.edit_message_text( 32 | text=f'{t}' 33 | f'👤 Akun: {account["email"]}\n\n' 34 | '📄 Detail VPS...', 35 | chat_id=call.from_user.id, 36 | message_id=call.message.message_id, 37 | parse_mode='HTML' 38 | ) 39 | 40 | try: 41 | droplets = digitalocean.Manager(token=account['token']).get_all_droplets() 42 | except Exception as e: 43 | bot.edit_message_text( 44 | text=f'{t}' 45 | f'👤 Akun: {account["email"]}\n\n' 46 | '⚠️ Kesalahan saat mengambil droplets: ' 47 | f'{str(e)}', 48 | chat_id=call.from_user.id, 49 | message_id=call.message.message_id, 50 | parse_mode='HTML' 51 | ) 52 | return 53 | 54 | markup = InlineKeyboardMarkup() 55 | 56 | if len(droplets) == 0: 57 | markup.add( 58 | InlineKeyboardButton( 59 | text='➕ Buat instance', 60 | callback_data=f'create_droplet?nf=select_region&doc_id={account.doc_id}' 61 | ) 62 | ) 63 | 64 | bot.edit_message_text( 65 | text=f'{t}' 66 | f'👤 Akun: {account["email"]}\n\n' 67 | '⚠️ Tidak ada instance', 68 | chat_id=call.from_user.id, 69 | message_id=call.message.message_id, 70 | parse_mode='HTML', 71 | reply_markup=markup 72 | ) 73 | return 74 | 75 | for droplet in droplets: 76 | markup.row( 77 | InlineKeyboardButton( 78 | text=f'{droplet.name} ({localize_region(droplet.region["slug"])}) ({droplet.size_slug})', 79 | callback_data=f'droplet_detail?doc_id={account.doc_id}&droplet_id={droplet.id}' 80 | ) 81 | ) 82 | 83 | bot.edit_message_text( 84 | text=f'{t}' 85 | f'👤 Akun: {account["email"]}\n\n' 86 | '🔢 Pilih instance', 87 | chat_id=call.from_user.id, 88 | message_id=call.message.message_id, 89 | parse_mode='HTML', 90 | reply_markup=markup 91 | ) 92 | -------------------------------------------------------------------------------- /modules/droplet_detail.py: -------------------------------------------------------------------------------- 1 | from telebot.types import ( 2 | CallbackQuery, 3 | InlineKeyboardMarkup, 4 | InlineKeyboardButton, 5 | ) 6 | 7 | import digitalocean 8 | 9 | from _bot import bot 10 | from utils.db import AccountsDB 11 | from utils.localizer import localize_region 12 | 13 | 14 | def droplet_detail(call: CallbackQuery, data: dict): 15 | doc_id = data['doc_id'][0] 16 | droplet_id = data['droplet_id'][0] 17 | t = 'Informasi Server\n\n' 18 | 19 | try: 20 | account = AccountsDB().get(doc_id=doc_id) 21 | except Exception as e: 22 | bot.edit_message_text( 23 | text=f'{t}' 24 | '⚠️ Kesalahan saat mengambil akun: ' 25 | f'{str(e)}', 26 | chat_id=call.from_user.id, 27 | message_id=call.message.message_id, 28 | parse_mode='HTML' 29 | ) 30 | return 31 | 32 | bot.edit_message_text( 33 | text=f'{t}' 34 | f'Akun: {account["email"]}\n\n' 35 | 'Mengambil informasi instan...', 36 | chat_id=call.from_user.id, 37 | message_id=call.message.message_id, 38 | parse_mode='HTML' 39 | ) 40 | 41 | try: 42 | droplet = digitalocean.Droplet().get_object( 43 | api_token=account['token'], 44 | droplet_id=droplet_id 45 | ) 46 | except Exception as e: 47 | bot.edit_message_text( 48 | text=f'{t}' 49 | f'Akun: {account["email"]}\n\n' 50 | '⚠️ Kesalahan saat mengambil informasi droplet: ' 51 | f'{str(e)}', 52 | chat_id=call.from_user.id, 53 | message_id=call.message.message_id, 54 | parse_mode='HTML' 55 | ) 56 | return 57 | markup = InlineKeyboardMarkup() 58 | markup.row( 59 | InlineKeyboardButton( 60 | text='🗑️ Hapus', 61 | callback_data=f'droplet_actions?doc_id={doc_id}&droplet_id={droplet_id}&a=delete' 62 | ), 63 | ) 64 | power_buttons = [] 65 | if droplet.status == 'active': 66 | power_buttons.extend([ 67 | InlineKeyboardButton( 68 | text='🛑 Matikan', 69 | callback_data=f'droplet_actions?doc_id={doc_id}&droplet_id={droplet_id}&a=shutdown' 70 | ), 71 | InlineKeyboardButton( 72 | text='🔄 Restart', 73 | callback_data=f'droplet_actions?doc_id={doc_id}&droplet_id={droplet_id}&a=reboot' 74 | ), 75 | ]) 76 | power_buttons.extend([ 77 | InlineKeyboardButton( 78 | text='🔨 Rebuild', 79 | callback_data=f'droplet_actions?doc_id={doc_id}&droplet_id={droplet_id}&a=rebuild' 80 | ), 81 | InlineKeyboardButton( 82 | text='🔑 Reset Password', 83 | callback_data=f'droplet_actions?doc_id={doc_id}&droplet_id={droplet_id}&a=reset_password' 84 | ) 85 | ]) 86 | else: 87 | power_buttons.append( 88 | InlineKeyboardButton( 89 | text='⚡ Nyalakan', 90 | callback_data=f'droplet_actions?doc_id={doc_id}&droplet_id={droplet_id}&a=power_on' 91 | ) 92 | ) 93 | markup.row(*power_buttons[:2]) 94 | markup.row(*power_buttons[2:]) 95 | markup.row( 96 | InlineKeyboardButton( 97 | text='🔄 Refresh', 98 | callback_data=f'droplet_detail?doc_id={account.doc_id}&droplet_id={droplet_id}' 99 | ), 100 | InlineKeyboardButton( 101 | text='🔙 Kembali', 102 | callback_data=f'list_droplets?doc_id={account.doc_id}' 103 | ) 104 | ) 105 | 106 | bot.edit_message_text( 107 | text=f'{t}' 108 | f'👤 Akun: {account["email"]}\n' 109 | f'🏷️ Nama: {droplet.name}\n' 110 | f'📏 Model: {droplet.size_slug}\n' 111 | f'🌍 Wilayah: {localize_region(droplet.region["slug"])}\n' 112 | f'💻 Sistem Operasi: {droplet.image["distribution"]} {droplet.image["name"]}\n' 113 | f'💾 Hard Disk: {droplet.disk} GB\n' 114 | f'🌐 IP Publik: {droplet.ip_address}\n' 115 | f'🔒 IP Privat: {droplet.private_ip_address}\n' 116 | f'📊 Status: {droplet.status}\n' 117 | f'📅 Dibuat pada: {droplet.created_at.split("T")[0]}\n', 118 | chat_id=call.from_user.id, 119 | message_id=call.message.message_id, 120 | parse_mode='HTML', 121 | reply_markup=markup 122 | ) 123 | -------------------------------------------------------------------------------- /modules/droplet_actions.py: -------------------------------------------------------------------------------- 1 | from telebot.types import CallbackQuery 2 | 3 | import digitalocean 4 | 5 | from _bot import bot 6 | from utils.db import AccountsDB 7 | 8 | 9 | def droplet_actions(call: CallbackQuery, data: dict): 10 | doc_id = data['doc_id'][0] 11 | droplet_id = data['droplet_id'][0] 12 | action = data['a'][0] 13 | 14 | try: 15 | account = AccountsDB().get(doc_id=doc_id) 16 | droplet = digitalocean.Droplet( 17 | token=account['token'], 18 | id=droplet_id 19 | ) 20 | except Exception as e: 21 | bot.edit_message_text( 22 | text=f'⚠️ Kesalahan saat mengambil akun atau droplet: {str(e)}', 23 | chat_id=call.from_user.id, 24 | message_id=call.message.message_id, 25 | parse_mode='HTML' 26 | ) 27 | return 28 | 29 | if action in globals(): 30 | globals()[action](call, droplet) 31 | 32 | 33 | def delete(call: CallbackQuery, droplet: digitalocean.Droplet): 34 | bot.edit_message_text( 35 | text=f'{call.message.html_text}\n\n' 36 | '🔄 Menghapus droplet...', 37 | chat_id=call.from_user.id, 38 | message_id=call.message.message_id, 39 | parse_mode='HTML' 40 | ) 41 | 42 | try: 43 | droplet.load() 44 | droplet.destroy() 45 | except Exception as e: 46 | bot.edit_message_text( 47 | text=f'⚠️ Kesalahan saat menghapus droplet: {str(e)}', 48 | chat_id=call.from_user.id, 49 | message_id=call.message.message_id, 50 | parse_mode='HTML' 51 | ) 52 | return 53 | 54 | bot.edit_message_text( 55 | text=f'{call.message.html_text}\n\n' 56 | f'✅ Droplet telah dihapus', 57 | chat_id=call.from_user.id, 58 | message_id=call.message.message_id, 59 | parse_mode='HTML' 60 | ) 61 | 62 | 63 | def shutdown(call: CallbackQuery, droplet: digitalocean.Droplet): 64 | bot.edit_message_text( 65 | text=f'{call.message.html_text}\n\n' 66 | '🔄 Mematikan droplet, silakan segarkan nanti', 67 | chat_id=call.from_user.id, 68 | message_id=call.message.message_id, 69 | reply_markup=call.message.reply_markup, 70 | parse_mode='HTML' 71 | ) 72 | 73 | try: 74 | droplet.load() 75 | droplet.shutdown() 76 | except Exception as e: 77 | bot.edit_message_text( 78 | text=f'⚠️ Kesalahan saat mematikan droplet: {str(e)}', 79 | chat_id=call.from_user.id, 80 | message_id=call.message.message_id, 81 | parse_mode='HTML' 82 | ) 83 | 84 | 85 | def reboot(call: CallbackQuery, droplet: digitalocean.Droplet): 86 | bot.edit_message_text( 87 | text=f'{call.message.html_text}\n\n' 88 | '🔄 Merestart droplet, silakan segarkan nanti', 89 | chat_id=call.from_user.id, 90 | message_id=call.message.message_id, 91 | reply_markup=call.message.reply_markup, 92 | parse_mode='HTML' 93 | ) 94 | 95 | try: 96 | droplet.load() 97 | droplet.reboot() 98 | except Exception as e: 99 | bot.edit_message_text( 100 | text=f'⚠️ Kesalahan saat merestart droplet: {str(e)}', 101 | chat_id=call.from_user.id, 102 | message_id=call.message.message_id, 103 | parse_mode='HTML' 104 | ) 105 | 106 | 107 | def power_on(call: CallbackQuery, droplet: digitalocean.Droplet): 108 | bot.edit_message_text( 109 | text=f'{call.message.html_text}\n\n' 110 | '🔄 Menyalakan droplet, silakan segarkan nanti', 111 | chat_id=call.from_user.id, 112 | message_id=call.message.message_id, 113 | reply_markup=call.message.reply_markup, 114 | parse_mode='HTML' 115 | ) 116 | 117 | try: 118 | droplet.load() 119 | droplet.power_on() 120 | except Exception as e: 121 | bot.edit_message_text( 122 | text=f'⚠️ Kesalahan saat menyalakan droplet: {str(e)}', 123 | chat_id=call.from_user.id, 124 | message_id=call.message.message_id, 125 | parse_mode='HTML' 126 | ) 127 | def rebuild(call: CallbackQuery, droplet: digitalocean.Droplet): 128 | bot.edit_message_text( 129 | text=f'{call.message.html_text}\n\n' 130 | '🔄 Membangun ulang droplet, silakan segarkan nanti', 131 | chat_id=call.from_user.id, 132 | message_id=call.message.message_id, 133 | reply_markup=call.message.reply_markup, 134 | parse_mode='HTML' 135 | ) 136 | 137 | try: 138 | droplet.load() 139 | droplet.rebuild() 140 | 141 | except Exception as e: 142 | bot.edit_message_text( 143 | text=f'⚠️ Kesalahan saat membangun ulang droplet: {str(e)}', 144 | chat_id=call.from_user.id, 145 | message_id=call.message.message_id, 146 | parse_mode='HTML' 147 | ) 148 | return 149 | 150 | bot.edit_message_text( 151 | text=f'{call.message.html_text}\n\n' 152 | f'✅ Droplet telah dibangun ulang\n' 153 | f'🔑 Password baru dikirim ke email', 154 | chat_id=call.from_user.id, 155 | message_id=call.message.message_id, 156 | parse_mode='HTML' 157 | ) 158 | def reset_password(call: CallbackQuery, droplet: digitalocean.Droplet): 159 | bot.edit_message_text( 160 | text=f'{call.message.html_text}\n\n' 161 | '🔄 Mereset password droplet, silakan segarkan nanti', 162 | chat_id=call.from_user.id, 163 | message_id=call.message.message_id, 164 | reply_markup=call.message.reply_markup, 165 | parse_mode='HTML' 166 | ) 167 | 168 | try: 169 | droplet.load() 170 | droplet.reset_root_password() 171 | except Exception as e: 172 | bot.edit_message_text( 173 | text=f'⚠️ Kesalahan saat mereset password droplet: {str(e)}', 174 | chat_id=call.from_user.id, 175 | message_id=call.message.message_id, 176 | parse_mode='HTML' 177 | ) 178 | return 179 | 180 | bot.edit_message_text( 181 | text=f'{call.message.html_text}\n\n' 182 | f'✅ Password droplet telah direset\n' 183 | f'🔑 Password baru dikirim ke email', 184 | chat_id=call.from_user.id, 185 | message_id=call.message.message_id, 186 | parse_mode='HTML' 187 | ) -------------------------------------------------------------------------------- /modules/create_droplet.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | from time import sleep 3 | 4 | from telebot.types import ( 5 | Message, 6 | CallbackQuery, 7 | InlineKeyboardMarkup, 8 | InlineKeyboardButton, 9 | ) 10 | 11 | import digitalocean 12 | 13 | from _bot import bot 14 | from utils.db import AccountsDB 15 | from utils.localizer import localize_region 16 | from utils.set_root_password_script import set_root_password_script 17 | from utils.password_generator import password_generator 18 | 19 | user_dict = {} 20 | 21 | t = '🚀 Buat Instance\n\n' 22 | 23 | 24 | def create_droplet(d: Union[Message, CallbackQuery], data: dict = None): 25 | data = data or {} 26 | next_func = data.get('nf', ['select_account'])[0] 27 | if next_func in globals(): 28 | data.pop('nf', None) 29 | args = [d] 30 | if len(data.keys()) > 0: 31 | args.append(data) 32 | 33 | globals()[next_func](*args) 34 | 35 | 36 | def select_account(d: Union[Message, CallbackQuery]): 37 | accounts = AccountsDB().all() 38 | markup = InlineKeyboardMarkup() 39 | for account in accounts: 40 | markup.add( 41 | InlineKeyboardButton( 42 | text=account['email'], 43 | callback_data=f'create_droplet?nf=select_region&doc_id={account.doc_id}' 44 | ) 45 | ) 46 | 47 | bot.send_message( 48 | text=f'{t}' 49 | '👤 Pilih Akun', 50 | chat_id=d.from_user.id, 51 | parse_mode='HTML', 52 | reply_markup=markup 53 | ) 54 | 55 | 56 | def select_region(call: CallbackQuery, data: dict): 57 | doc_id = data['doc_id'][0] 58 | 59 | account = AccountsDB().get(doc_id=doc_id) 60 | user_dict[call.from_user.id] = { 61 | 'account': account 62 | } 63 | 64 | _t = t + f'👤 Akun: {account["email"]}\n\n' 65 | 66 | bot.edit_message_text( 67 | text=f'{_t}' 68 | f'🌍 Mengambil daftar Wilayah...', 69 | chat_id=call.from_user.id, 70 | message_id=call.message.message_id, 71 | parse_mode='HTML' 72 | ) 73 | 74 | try: 75 | regions = digitalocean.Manager(token=account['token']).get_all_regions() 76 | except Exception as e: 77 | bot.edit_message_text( 78 | text=f'{_t}' 79 | '⚠️ Kesalahan saat mengambil Wilayah: ' 80 | f'{str(e)}', 81 | chat_id=call.from_user.id, 82 | message_id=call.message.message_id, 83 | parse_mode='HTML' 84 | ) 85 | return 86 | 87 | markup = InlineKeyboardMarkup(row_width=2) 88 | buttons = [] 89 | for region in regions: 90 | if region.available: 91 | buttons.append( 92 | InlineKeyboardButton( 93 | text=localize_region(slug=region.slug), 94 | callback_data=f'create_droplet?nf=select_size®ion={region.slug}' 95 | ) 96 | ) 97 | markup.add(*buttons) 98 | 99 | bot.edit_message_text( 100 | text=f'{_t}' 101 | f'🌍 Pilih Wilayah', 102 | chat_id=call.from_user.id, 103 | message_id=call.message.message_id, 104 | reply_markup=markup, 105 | parse_mode='HTML' 106 | ) 107 | 108 | 109 | def select_size(call: CallbackQuery, data: dict): 110 | region_slug = data['region'][0] 111 | 112 | user_dict[call.from_user.id].update({ 113 | 'region_slug': region_slug 114 | }) 115 | 116 | _t = t + f'👤 Akun: {user_dict[call.from_user.id]["account"]["email"]}\n' \ 117 | f'🌍 Wilayah: {region_slug}\n\n' 118 | 119 | bot.edit_message_text( 120 | text=f'{_t}' 121 | f'📏 Mengambil daftar Ukuran...', 122 | chat_id=call.from_user.id, 123 | message_id=call.message.message_id, 124 | parse_mode='HTML' 125 | ) 126 | 127 | try: 128 | sizes = digitalocean.Manager(token=user_dict[call.from_user.id]['account']['token']).get_all_sizes() 129 | except Exception as e: 130 | bot.edit_message_text( 131 | text=f'{_t}' 132 | '⚠️ Kesalahan saat mengambil Ukuran: ' 133 | f'{str(e)}', 134 | chat_id=call.from_user.id, 135 | message_id=call.message.message_id, 136 | parse_mode='HTML' 137 | ) 138 | return 139 | 140 | markup = InlineKeyboardMarkup(row_width=2) 141 | buttons = [] 142 | for size in sizes: 143 | if region_slug in size.regions: 144 | buttons.append( 145 | InlineKeyboardButton( 146 | text=size.slug, 147 | callback_data=f'create_droplet?nf=select_os&size={size.slug}' 148 | ) 149 | ) 150 | markup.add(*buttons) 151 | markup.row( 152 | InlineKeyboardButton( 153 | text='⬅️ Sebelumnya', 154 | callback_data=f'create_droplet?nf=select_region&doc_id={user_dict[call.from_user.id]["account"].doc_id}' 155 | ) 156 | ) 157 | 158 | bot.edit_message_text( 159 | text=f'{_t}' 160 | f'📏 Pilih Ukuran', 161 | chat_id=call.from_user.id, 162 | message_id=call.message.message_id, 163 | reply_markup=markup, 164 | parse_mode='HTML' 165 | ) 166 | 167 | 168 | def select_os(d: Union[Message, CallbackQuery], data: dict): 169 | size_slug = data['size'][0] 170 | 171 | user_dict[d.from_user.id].update({ 172 | 'size_slug': size_slug 173 | }) 174 | 175 | _t = t + f'👤 Akun: {user_dict[d.from_user.id]["account"]["email"]}\n' \ 176 | f'🌍 Wilayah: {user_dict[d.from_user.id]["region_slug"]}\n' \ 177 | f'📏 Ukuran: {size_slug}\n\n' 178 | 179 | def get_os_markup(): 180 | try: 181 | images = digitalocean.Manager(token=user_dict[d.from_user.id]['account']['token']).get_distro_images() 182 | except Exception as e: 183 | bot.edit_message_text( 184 | text=f'{_t}' 185 | '⚠️ Kesalahan saat mengambil OS: ' 186 | f'{str(e)}', 187 | chat_id=d.from_user.id, 188 | message_id=d.message.message_id, 189 | parse_mode='HTML' 190 | ) 191 | return InlineKeyboardMarkup() 192 | 193 | markup = InlineKeyboardMarkup(row_width=2) 194 | buttons = [] 195 | for image in images: 196 | if image.distribution in ['Ubuntu', 'CentOS', 'Debian'] \ 197 | and image.public \ 198 | and image.status == 'available' \ 199 | and user_dict[d.from_user.id]["region_slug"] in image.regions: 200 | buttons.append( 201 | InlineKeyboardButton( 202 | text=f'{image.distribution} {image.name}', 203 | callback_data=f'create_droplet?nf=get_name&image={image.slug}' 204 | ) 205 | ) 206 | markup.add(*buttons) 207 | markup.row( 208 | InlineKeyboardButton( 209 | text='⬅️ Sebelumnya', 210 | callback_data=f'create_droplet?nf=select_size®ion={user_dict[d.from_user.id]["region_slug"]}' 211 | ) 212 | ) 213 | 214 | return markup 215 | 216 | if type(d) == Message: 217 | msg = bot.send_message( 218 | text=f'{_t}' 219 | f'🖼️ Mengambil daftar OS...', 220 | chat_id=d.from_user.id, 221 | parse_mode='HTML' 222 | ) 223 | bot.edit_message_text( 224 | text=f'{_t}' 225 | f'🖼️ Pilih OS', 226 | chat_id=d.from_user.id, 227 | message_id=msg.message_id, 228 | reply_markup=get_os_markup(), 229 | parse_mode='HTML' 230 | ) 231 | 232 | elif type(d) == CallbackQuery: 233 | bot.edit_message_text( 234 | text=f'{_t}' 235 | f'🖼️ Mengambil daftar OS...', 236 | chat_id=d.from_user.id, 237 | message_id=d.message.message_id, 238 | parse_mode='HTML' 239 | ) 240 | bot.edit_message_text( 241 | text=f'{_t}' 242 | f'🖼️ Pilih OS', 243 | chat_id=d.from_user.id, 244 | message_id=d.message.message_id, 245 | reply_markup=get_os_markup(), 246 | parse_mode='HTML' 247 | ) 248 | 249 | 250 | def get_name(call: CallbackQuery, data: dict): 251 | image_slug = data['image'][0] 252 | 253 | user_dict[call.from_user.id].update({ 254 | 'image_slug': image_slug 255 | }) 256 | 257 | _t = t + f'👤 Akun: {user_dict[call.from_user.id]["account"]["email"]}\n' \ 258 | f'🌍 Wilayah: {user_dict[call.from_user.id]["region_slug"]}\n' \ 259 | f'📏 Ukuran: {user_dict[call.from_user.id]["size_slug"]}\n' \ 260 | f'🖼️ OS: {image_slug}\n\n' 261 | 262 | msg = bot.edit_message_text( 263 | text=f'{_t}' 264 | '📝 Harap balas dengan Nama Instance, contoh: FighterTunnel\n\n' 265 | '/back ⬅️ Sebelumnya', 266 | chat_id=call.from_user.id, 267 | message_id=call.message.message_id, 268 | parse_mode='HTML' 269 | ) 270 | bot.register_next_step_handler(msg, ask_create) 271 | 272 | 273 | def ask_create(m: Message): 274 | if m.text == '/back': 275 | select_os(m, data={'size': [user_dict[m.from_user.id]["size_slug"]]}) 276 | return 277 | 278 | _t = t + f'👤 Akun: {user_dict[m.from_user.id]["account"]["email"]}\n' \ 279 | f'🌍 Wilayah: {user_dict[m.from_user.id]["region_slug"]}\n' \ 280 | f'📏 Ukuran: {user_dict[m.from_user.id]["size_slug"]}\n' \ 281 | f'🖼️ OS: {user_dict[m.from_user.id]["image_slug"]}\n' \ 282 | f'📝 Nama: {m.text}\n\n' 283 | markup = InlineKeyboardMarkup(row_width=2) 284 | markup.add( 285 | InlineKeyboardButton( 286 | text='⬅️ Sebelumnya', 287 | callback_data=f'create_droplet?nf=get_name&image={user_dict[m.from_user.id]["image_slug"]}' 288 | ), 289 | InlineKeyboardButton( 290 | text='❌ Membatalkan', 291 | callback_data='create_droplet?nf=cancel_create' 292 | ), 293 | ) 294 | markup.row( 295 | InlineKeyboardButton( 296 | text='✅ Buat', 297 | callback_data=f'create_droplet?nf=confirm_create&name={m.text}' 298 | ) 299 | ) 300 | 301 | bot.send_message( 302 | text=_t, 303 | chat_id=m.from_user.id, 304 | reply_markup=markup, 305 | parse_mode='HTML' 306 | ) 307 | 308 | 309 | def cancel_create(call: CallbackQuery): 310 | bot.edit_message_text( 311 | text=f'{call.message.html_text}\n\n' 312 | '❌ Membatalkan', 313 | chat_id=call.from_user.id, 314 | message_id=call.message.message_id, 315 | parse_mode='HTML' 316 | ) 317 | 318 | 319 | def confirm_create(call: CallbackQuery, data: dict): 320 | droplet_name = data['name'][0] 321 | password = password_generator() 322 | 323 | bot.edit_message_text( 324 | text=f'{call.message.html_text}\n\n' 325 | '🔄 Membuat Instance...', 326 | chat_id=call.from_user.id, 327 | message_id=call.message.message_id, 328 | parse_mode='HTML' 329 | ) 330 | try: 331 | droplet = digitalocean.Droplet( 332 | token=user_dict[call.from_user.id]['account']['token'], 333 | name=droplet_name, 334 | region=user_dict[call.from_user.id]['region_slug'], 335 | image=user_dict[call.from_user.id]['image_slug'], 336 | size_slug=user_dict[call.from_user.id]['size_slug'], 337 | user_data=set_root_password_script(password) 338 | ) 339 | droplet.create() 340 | 341 | droplet_actions = droplet.get_actions() 342 | for action in droplet_actions: 343 | while action.status != 'completed': 344 | sleep(3) 345 | action.load() 346 | droplet.load() 347 | 348 | # Menunggu IP address siap 349 | while not droplet.ip_address: 350 | sleep(3) 351 | droplet.load() 352 | except Exception as e: 353 | bot.edit_message_text( 354 | text=f'{call.message.html_text}\n\n' 355 | '⚠️ Kesalahan saat membuat Instance: ' 356 | f'{str(e)}', 357 | chat_id=call.from_user.id, 358 | message_id=call.message.message_id, 359 | parse_mode='HTML' 360 | ) 361 | return 362 | 363 | markup = InlineKeyboardMarkup() 364 | markup.row( 365 | InlineKeyboardButton( 366 | text='🔍 Periksa Detailnya', 367 | callback_data=f'droplet_detail?' 368 | f'doc_id={user_dict[call.from_user.id]["account"].doc_id}&' 369 | f'droplet_id={droplet.id}' 370 | ) 371 | ) 372 | 373 | bot.edit_message_text( 374 | text=f'{call.message.html_text}\n' 375 | f'🌐 IP: {droplet.ip_address}\n' 376 | f'🔑 Kata Sandi: {password}\n\n' 377 | '✅ Pembuatan Server Selesai', 378 | chat_id=call.from_user.id, 379 | reply_markup=markup, 380 | message_id=call.message.message_id, 381 | parse_mode='HTML' 382 | ) 383 | --------------------------------------------------------------------------------