mirror of
https://github.com/yasirarism/MissKatyPyro.git
synced 2025-12-29 09:44:50 +00:00
Added Paydisini Integration (#309)
This commit is contained in:
parent
638cde6dd7
commit
3f6cd58db2
8 changed files with 176 additions and 4 deletions
|
|
@ -13,7 +13,7 @@ FROM yasirarism/misskaty-docker:py3.12
|
||||||
ENV HOSTNAME=yasir-server
|
ENV HOSTNAME=yasir-server
|
||||||
# Copy Files
|
# Copy Files
|
||||||
COPY . .
|
COPY . .
|
||||||
# Instal pip package
|
# Instal pip package if you use free depedencies
|
||||||
# RUN pip3 install --no-cache-dir -r requirements.txt
|
# RUN pip3 install --no-cache-dir -r requirements.txt
|
||||||
# Set CMD Bot
|
# Set CMD Bot
|
||||||
CMD ["bash", "start.sh"]
|
CMD ["bash", "start.sh"]
|
||||||
|
|
|
||||||
16
database/payment_db.py
Normal file
16
database/payment_db.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
from database import dbname
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
autopay = dbname["autpay"]
|
||||||
|
|
||||||
|
|
||||||
|
async def delete_autopay(uniqueCode: str):
|
||||||
|
await autopay.delete_one({"_id": uniqueCode})
|
||||||
|
|
||||||
|
async def get_autopay(self, uniqueCode: str):
|
||||||
|
exists = await autopay.find_one({"_id": uniqueCode})
|
||||||
|
return exists
|
||||||
|
|
||||||
|
async def autopay_update(self, msg_id: Optional[int] = "", note: Optional[str] = "", user_id: Optional[int] = "", amount: Optional[int] = "", status: Optional[str] = "", uniqueCode: Optional[str] = "", createdAt: Optional[str] = ""):
|
||||||
|
data = {"msg_id": msg_id, "note": note, "user_id": user_id, "amount": amount, "status": status, "createdAt": createdAt}
|
||||||
|
await autopay.update_one({"_id": uniqueCode}, {"$set": data}, upsert=True)
|
||||||
|
|
@ -8,12 +8,13 @@ from asyncio import get_event_loop
|
||||||
from faulthandler import enable as faulthandler_enable
|
from faulthandler import enable as faulthandler_enable
|
||||||
from logging import ERROR, INFO, StreamHandler, basicConfig, getLogger, handlers
|
from logging import ERROR, INFO, StreamHandler, basicConfig, getLogger, handlers
|
||||||
|
|
||||||
import uvloop
|
import uvloop, uvicorn
|
||||||
from apscheduler.jobstores.mongodb import MongoDBJobStore
|
from apscheduler.jobstores.mongodb import MongoDBJobStore
|
||||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||||
from async_pymongo import AsyncClient
|
from async_pymongo import AsyncClient
|
||||||
from pymongo import MongoClient
|
from pymongo import MongoClient
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
from web.webserver import api
|
||||||
|
|
||||||
from misskaty.vars import (
|
from misskaty.vars import (
|
||||||
API_HASH,
|
API_HASH,
|
||||||
|
|
@ -21,6 +22,7 @@ from misskaty.vars import (
|
||||||
BOT_TOKEN,
|
BOT_TOKEN,
|
||||||
DATABASE_NAME,
|
DATABASE_NAME,
|
||||||
DATABASE_URI,
|
DATABASE_URI,
|
||||||
|
PORT,
|
||||||
TZ,
|
TZ,
|
||||||
USER_SESSION,
|
USER_SESSION,
|
||||||
)
|
)
|
||||||
|
|
@ -83,6 +85,11 @@ jobstores = {
|
||||||
}
|
}
|
||||||
scheduler = AsyncIOScheduler(jobstores=jobstores, timezone=TZ)
|
scheduler = AsyncIOScheduler(jobstores=jobstores, timezone=TZ)
|
||||||
|
|
||||||
|
async def run_wsgi():
|
||||||
|
config = uvicorn.Config(api, host="0.0.0.0", port=int(PORT))
|
||||||
|
server = uvicorn.Server(config)
|
||||||
|
await server.serve()
|
||||||
|
|
||||||
app.start()
|
app.start()
|
||||||
BOT_ID = app.me.id
|
BOT_ID = app.me.id
|
||||||
BOT_NAME = app.me.first_name
|
BOT_NAME = app.me.first_name
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ from misskaty import (
|
||||||
app,
|
app,
|
||||||
get_event_loop,
|
get_event_loop,
|
||||||
scheduler,
|
scheduler,
|
||||||
|
run_wsgi
|
||||||
)
|
)
|
||||||
from misskaty.plugins import ALL_MODULES
|
from misskaty.plugins import ALL_MODULES
|
||||||
from misskaty.plugins.web_scraper import web
|
from misskaty.plugins.web_scraper import web
|
||||||
|
|
@ -56,7 +57,6 @@ async def start_bot():
|
||||||
LOGGER.info(bot_modules)
|
LOGGER.info(bot_modules)
|
||||||
LOGGER.info("+===============+===============+===============+===============+")
|
LOGGER.info("+===============+===============+===============+===============+")
|
||||||
LOGGER.info("[INFO]: BOT STARTED AS @%s!", BOT_USERNAME)
|
LOGGER.info("[INFO]: BOT STARTED AS @%s!", BOT_USERNAME)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
LOGGER.info("[INFO]: SENDING ONLINE STATUS")
|
LOGGER.info("[INFO]: SENDING ONLINE STATUS")
|
||||||
for i in SUDO:
|
for i in SUDO:
|
||||||
|
|
@ -73,6 +73,7 @@ async def start_bot():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOGGER.error(str(e))
|
LOGGER.error(str(e))
|
||||||
scheduler.start()
|
scheduler.start()
|
||||||
|
asyncio.create_task(run_wsgi())
|
||||||
if "web" not in await dbname.list_collection_names():
|
if "web" not in await dbname.list_collection_names():
|
||||||
webdb = dbname["web"]
|
webdb = dbname["web"]
|
||||||
for key, value in web.items():
|
for key, value in web.items():
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@ import html
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import hashlib
|
||||||
import pickle
|
import pickle
|
||||||
import platform
|
import platform
|
||||||
import privatebinapi
|
import privatebinapi
|
||||||
import re
|
import re
|
||||||
|
import secrets
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
@ -22,6 +24,7 @@ import cloudscraper
|
||||||
import requests
|
import requests
|
||||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
from urllib.parse import quote
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
from psutil import Process, boot_time, cpu_count, cpu_percent
|
from psutil import Process, boot_time, cpu_count, cpu_percent
|
||||||
from psutil import disk_usage as disk_usage_percent
|
from psutil import disk_usage as disk_usage_percent
|
||||||
|
|
@ -44,6 +47,7 @@ from pyrogram.types import (
|
||||||
LabeledPrice,
|
LabeledPrice,
|
||||||
Message,
|
Message,
|
||||||
PreCheckoutQuery,
|
PreCheckoutQuery,
|
||||||
|
WebAppInfo,
|
||||||
)
|
)
|
||||||
|
|
||||||
from database.gban_db import add_gban_user, is_gbanned_user, remove_gban_user
|
from database.gban_db import add_gban_user, is_gbanned_user, remove_gban_user
|
||||||
|
|
@ -55,7 +59,8 @@ from misskaty.helper.functions import extract_user, extract_user_and_reason
|
||||||
from misskaty.helper.http import fetch
|
from misskaty.helper.http import fetch
|
||||||
from misskaty.helper.human_read import get_readable_file_size, get_readable_time
|
from misskaty.helper.human_read import get_readable_file_size, get_readable_time
|
||||||
from misskaty.helper.localization import use_chat_lang
|
from misskaty.helper.localization import use_chat_lang
|
||||||
from misskaty.vars import AUTO_RESTART, COMMAND_HANDLER, LOG_CHANNEL, SUDO
|
from database.payment_db import autopay_update
|
||||||
|
from misskaty.vars import AUTO_RESTART, COMMAND_HANDLER, LOG_CHANNEL, SUDO, PAYDISINI_CHANNEL_ID, PAYDISINI_KEY
|
||||||
|
|
||||||
__MODULE__ = "DevCommand"
|
__MODULE__ = "DevCommand"
|
||||||
__HELP__ = """
|
__HELP__ = """
|
||||||
|
|
@ -179,6 +184,45 @@ async def log_file(_, ctx: Message, strings):
|
||||||
else:
|
else:
|
||||||
await msg.edit_msg("Unsupported parameter")
|
await msg.edit_msg("Unsupported parameter")
|
||||||
|
|
||||||
|
@app.on_message(filters.command(["payment"], COMMAND_HANDLER))
|
||||||
|
async def payment(client: Client, message: Message):
|
||||||
|
api_url = 'https://api.paydisini.co.id/v1/'
|
||||||
|
api_key = PAYDISINI_KEY
|
||||||
|
unique_id = f"VIP-{secrets.token_hex(5)}"
|
||||||
|
amount = "10000" if len(message.command) == 1 else str(message.command[1])
|
||||||
|
id_ = message.from_user.id if message.chat.id != message.from_user.id else message.chat.id
|
||||||
|
valid_time = str(5*60)
|
||||||
|
service_id = PAYDISINI_CHANNEL_ID
|
||||||
|
|
||||||
|
params = {
|
||||||
|
'key': api_key,
|
||||||
|
'request': 'new',
|
||||||
|
'unique_code': unique_id,
|
||||||
|
'service': service_id,
|
||||||
|
'amount': amount,
|
||||||
|
'note': f'MissKaty Support by YS Dev',
|
||||||
|
'valid_time': valid_time,
|
||||||
|
'type_fee': '1',
|
||||||
|
'payment_guide': True,
|
||||||
|
'signature': hashlib.md5((api_key + unique_id + service_id + amount + valid_time + 'NewTransaction').encode()).hexdigest(),
|
||||||
|
'return_url': f'https://t.me/{client.me.username}?start'
|
||||||
|
}
|
||||||
|
# if id_ in user_data and user_data[id_].get("is_auth"):
|
||||||
|
# return await message.reply("Already Authorized!")
|
||||||
|
rget = await fetch.post(api_url, data=params)
|
||||||
|
if rget.status_code != 200:
|
||||||
|
return await message.reply("ERROR: Maybe your IP is not whitelisted or have another error from api.")
|
||||||
|
res = rget.json()
|
||||||
|
if not res.get("success"):
|
||||||
|
return await message.reply(res["msg"])
|
||||||
|
qr_photo = f"https://api.qrserver.com/v1/create-qr-code/?size=300x300&data={quote(res['data']['qr_content'])}"
|
||||||
|
capt = f"𝗠𝗲𝗻𝘂𝗻𝗴𝗴𝘂 𝗽𝗲𝗺𝗯𝗮𝘆𝗮𝗿𝗮𝗻\nKode: {res['data']['unique_code']}\nNote: {res['data']['note']}\nHarga: {res['data']['amount']}\nFee: {res['data']['fee']}\nExpired: {res['data']['expired']}\n\n"
|
||||||
|
payment_guide = f"<b>{res['payment_guide'][0]['title']}:</b>\n" + "\n".join(f"{i+1}. {step}" for i, step in enumerate(res["payment_guide"][0]['content']))
|
||||||
|
if message.chat.type.value != "private":
|
||||||
|
msg = await message.reply_photo(qr_photo, caption=capt+payment_guide, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text="Payment Web", url=res["data"]["checkout_url_v2"])]]), quote=True)
|
||||||
|
else:
|
||||||
|
msg = await message.reply_photo(qr_photo, caption=capt+payment_guide, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text="Payment Web", web_app=WebAppInfo(url=res["data"]["checkout_url_v2"]))]]), quote=True)
|
||||||
|
await autopay_update(msg.id, res["data"]["note"], id_, res['data']['amount'], res['data']['status'], res['data']['unique_code'], res['data']['created_at'])
|
||||||
|
|
||||||
@app.on_message(filters.command(["donate"], COMMAND_HANDLER))
|
@app.on_message(filters.command(["donate"], COMMAND_HANDLER))
|
||||||
async def donate(self: Client, ctx: Message):
|
async def donate(self: Client, ctx: Message):
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ LOG_GROUP_ID = environ.get("LOG_GROUP_ID")
|
||||||
USER_SESSION = environ.get("USER_SESSION")
|
USER_SESSION = environ.get("USER_SESSION")
|
||||||
DATABASE_NAME = environ.get("DATABASE_NAME", "MissKatyDB")
|
DATABASE_NAME = environ.get("DATABASE_NAME", "MissKatyDB")
|
||||||
TZ = environ.get("TZ", "Asia/Jakarta")
|
TZ = environ.get("TZ", "Asia/Jakarta")
|
||||||
|
PORT = environ.get("PORT", 80)
|
||||||
COMMAND_HANDLER = environ.get("COMMAND_HANDLER", "! /").split()
|
COMMAND_HANDLER = environ.get("COMMAND_HANDLER", "! /").split()
|
||||||
SUDO = list(
|
SUDO = list(
|
||||||
{
|
{
|
||||||
|
|
@ -64,6 +65,8 @@ SUPPORT_CHAT = environ.get("SUPPORT_CHAT", "YasirPediaChannel")
|
||||||
AUTO_RESTART = environ.get("AUTO_RESTART", False)
|
AUTO_RESTART = environ.get("AUTO_RESTART", False)
|
||||||
OPENAI_KEY = environ.get("OPENAI_KEY")
|
OPENAI_KEY = environ.get("OPENAI_KEY")
|
||||||
GOOGLEAI_KEY = environ.get("GOOGLEAI_KEY")
|
GOOGLEAI_KEY = environ.get("GOOGLEAI_KEY")
|
||||||
|
PAYDISINI_KEY = environ.get("PAYDISINI_KEY")
|
||||||
|
PAYDISINI_CHANNEL_ID = environ.get("PAYDISINI_CHANNEL_ID", "17")
|
||||||
|
|
||||||
## Config For AUtoForwarder
|
## Config For AUtoForwarder
|
||||||
# Forward From Chat ID
|
# Forward From Chat ID
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,6 @@ GitPython
|
||||||
aiofiles
|
aiofiles
|
||||||
uvloop==0.19.0
|
uvloop==0.19.0
|
||||||
lxml_html_clean
|
lxml_html_clean
|
||||||
|
fastapi
|
||||||
|
uvicorn
|
||||||
|
python-multipart
|
||||||
|
|
|
||||||
98
web/webserver.py
Normal file
98
web/webserver.py
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
from logging import INFO, StreamHandler, basicConfig, getLogger, ERROR, handlers
|
||||||
|
from os import path
|
||||||
|
from time import time
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from fastapi import FastAPI, Request
|
||||||
|
from fastapi.responses import HTMLResponse, JSONResponse
|
||||||
|
from starlette.exceptions import HTTPException
|
||||||
|
from psutil import boot_time, disk_usage, net_io_counters
|
||||||
|
from contextlib import suppress
|
||||||
|
from asyncio import to_thread, subprocess, create_subprocess_shell
|
||||||
|
from apscheduler.triggers.date import DateTrigger
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
api = FastAPI()
|
||||||
|
|
||||||
|
basicConfig(
|
||||||
|
level=INFO,
|
||||||
|
format="[%(levelname)s] - [%(asctime)s - %(name)s - %(message)s] -> [%(module)s:%(lineno)d]",
|
||||||
|
datefmt="%d-%b-%y %H:%M:%S",
|
||||||
|
handlers=[
|
||||||
|
handlers.RotatingFileHandler(
|
||||||
|
"MissKatyLogs.txt", mode="w+", maxBytes=5242880, backupCount=1
|
||||||
|
),
|
||||||
|
StreamHandler(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
botStartTime = time()
|
||||||
|
|
||||||
|
LOGGER = getLogger(__name__)
|
||||||
|
getLogger("fastapi").setLevel(ERROR)
|
||||||
|
|
||||||
|
@api.post("/callback")
|
||||||
|
async def autopay(request: Request):
|
||||||
|
from misskaty import app
|
||||||
|
from database.payment_db import delete_autopay, get_autopay
|
||||||
|
from misskaty.vars import PAYDISINI_KEY, OWNER_ID
|
||||||
|
data = await request.form()
|
||||||
|
client_ip = request.client.host
|
||||||
|
if PAYDISINI_KEY != data["key"] and client_ip != "84.247.150.90":
|
||||||
|
raise HTTPException(status_code=403, detail="Access forbidden")
|
||||||
|
signature_data = f"{PAYDISINI_KEY}{data['unique_code']}CallbackStatus"
|
||||||
|
gen_signature = hashlib.md5(signature_data.encode()).hexdigest()
|
||||||
|
if gen_signature != data["signature"]:
|
||||||
|
raise HTTPException(status_code=403, detail="Invalid Signature")
|
||||||
|
unique_code = data['unique_code']
|
||||||
|
status = data['status']
|
||||||
|
exp_date = (datetime.now(jkt) + timedelta(days=30)).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
r = await get_autopay(unique_code)
|
||||||
|
msg = f"╭────〔 <b>TRANSAKSI SUKSES🎉</b> 〕──\n│・ <b>Transaksi ID :</b> {unique_code}\n│・ <b>Product :</b> MissKaty Support by YS Dev\n│・ <b>Durasi :</b> 30 hari\n│・ <b>Total Dibayar :</b> {r.get('amount')}\n│・ Langganan Berakhir: {exp_date}\n╰─────────"
|
||||||
|
if not r:
|
||||||
|
return JSONResponse({"status": false, "data": "Data not found on DB"}, 404)
|
||||||
|
if status == "Success":
|
||||||
|
with suppress(Exception):
|
||||||
|
await bot.send_message(r.get("user_id"), f"{msg}\n\nJika ada pertanyaan silahkan hubungi pemilik bot ini.")
|
||||||
|
await bot.delete_messages(r.get("user_id"), r.get("msg_id"))
|
||||||
|
await bot.send_message(OWNER_ID, msg)
|
||||||
|
await delete_autopay(unique_code)
|
||||||
|
return JSONResponse({"status": status, "msg": "Pesanan berhasil dibayar oleh customer."}, 200)
|
||||||
|
else:
|
||||||
|
with suppress(Exception):
|
||||||
|
await bot.send_message(r.get("user_id"), "QRIS Telah Expired, Silahkan Buat Transaksi Baru.")
|
||||||
|
await bot.delete_messages(r.get("user_id"), r.get("msg_id"))
|
||||||
|
await delete_autopay(unique_code)
|
||||||
|
return JSONResponse({"status": status, "msg": "Pesanan telah dibatalkan/gagal dibayar."}, 403)
|
||||||
|
|
||||||
|
@api.get("/status")
|
||||||
|
async def status():
|
||||||
|
from misskaty.helper.human_read import get_readable_file_size, get_readable_time
|
||||||
|
bot_uptime = get_readable_time(time() - botStartTime)
|
||||||
|
uptime = get_readable_time(time() - boot_time())
|
||||||
|
sent = get_readable_file_size(net_io_counters().bytes_sent)
|
||||||
|
recv = get_readable_file_size(net_io_counters().bytes_recv)
|
||||||
|
if path.exists(".git"):
|
||||||
|
commit_date = (await (await create_subprocess_shell("git log -1 --date=format:'%y/%m/%d %H:%M' --pretty=format:'%cd'", stdout=subprocess.PIPE, stderr=subprocess.STDOUT)).communicate())[0].decode()
|
||||||
|
else:
|
||||||
|
commit_date = "No UPSTREAM_REPO"
|
||||||
|
return {
|
||||||
|
"commit_date": commit_date,
|
||||||
|
"uptime": uptime,
|
||||||
|
"on_time": bot_uptime,
|
||||||
|
"free_disk": get_readable_file_size(disk_usage(".").free),
|
||||||
|
"total_disk": get_readable_file_size(disk_usage(".").total),
|
||||||
|
"network": {
|
||||||
|
"sent": sent,
|
||||||
|
"recv": recv,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@api.api_route("/")
|
||||||
|
async def homepage():
|
||||||
|
return "Hello World"
|
||||||
|
|
||||||
|
|
||||||
|
@api.exception_handler(HTTPException)
|
||||||
|
async def page_not_found(request: Request, exc: HTTPException):
|
||||||
|
return HTMLResponse(content=f"<h1>Error: {exc}</h1>", status_code=exc.status_code)
|
||||||
Loading…
Reference in a new issue