RubigramClient 1.3.3__tar.gz → 1.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of RubigramClient might be problematic. Click here for more details.
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/PKG-INFO +1 -1
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/RubigramClient.egg-info/PKG-INFO +1 -1
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/RubigramClient.egg-info/SOURCES.txt +2 -0
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/pyproject.toml +1 -1
- rubigramclient-1.3.4/rubigram/__init__.py +4 -0
- rubigramclient-1.3.4/rubigram/client.py +34 -0
- rubigramclient-1.3.4/rubigram/filters.py +53 -0
- rubigramclient-1.3.4/rubigram/method.py +208 -0
- rubigramclient-1.3.4/rubigram/network.py +30 -0
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/rubigram/types.py +8 -4
- rubigramclient-1.3.3/rubigram/__init__.py +0 -2
- rubigramclient-1.3.3/rubigram/client.py +0 -317
- rubigramclient-1.3.3/rubigram/filters.py +0 -58
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/LICENSE +0 -0
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/README.md +0 -0
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/RubigramClient.egg-info/dependency_links.txt +0 -0
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/RubigramClient.egg-info/requires.txt +0 -0
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/RubigramClient.egg-info/top_level.txt +0 -0
- {rubigramclient-1.3.3 → rubigramclient-1.3.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: RubigramClient
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.4
|
|
4
4
|
Summary: A simple and flexible Python library for building advanced Rubika bots with powerful message handling, inline buttons, and custom filters.
|
|
5
5
|
Author-email: Javad RZ <Javad.Py1385@gmail.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: RubigramClient
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.4
|
|
4
4
|
Summary: A simple and flexible Python library for building advanced Rubika bots with powerful message handling, inline buttons, and custom filters.
|
|
5
5
|
Author-email: Javad RZ <Javad.Py1385@gmail.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "RubigramClient"
|
|
3
|
-
version = "1.3.
|
|
3
|
+
version = "1.3.4"
|
|
4
4
|
description = "A simple and flexible Python library for building advanced Rubika bots with powerful message handling, inline buttons, and custom filters."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.7"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from rubigram.types import Update, InlineMessage
|
|
2
|
+
from rubigram.method import Method
|
|
3
|
+
from aiohttp import web
|
|
4
|
+
|
|
5
|
+
class Client(Method):
|
|
6
|
+
def __init__(self, token: str):
|
|
7
|
+
self.messages_handler = []
|
|
8
|
+
super().__init__(token)
|
|
9
|
+
|
|
10
|
+
def on_message(self, *filters):
|
|
11
|
+
def decorator(func):
|
|
12
|
+
async def wrapped(client, update):
|
|
13
|
+
if all(f(update) for f in filters):
|
|
14
|
+
await func(client, update)
|
|
15
|
+
self.messages_handler.append(wrapped)
|
|
16
|
+
return func
|
|
17
|
+
return decorator
|
|
18
|
+
|
|
19
|
+
async def update(self, data: dict):
|
|
20
|
+
event = Update.read(data["update"]) if data.get("update") else InlineMessage.read(data["inline_message"])
|
|
21
|
+
for handler in self.messages_handler:
|
|
22
|
+
await handler(self, event)
|
|
23
|
+
|
|
24
|
+
def run(self):
|
|
25
|
+
routes = web.RouteTableDef()
|
|
26
|
+
@routes.post("/receiveUpdate")
|
|
27
|
+
@routes.post("/receiveInlineMessage")
|
|
28
|
+
async def webhook(request):
|
|
29
|
+
data = await request.json()
|
|
30
|
+
await self.update(data)
|
|
31
|
+
return web.json_response({"status": "ok"})
|
|
32
|
+
app = web.Application()
|
|
33
|
+
app.add_routes(routes)
|
|
34
|
+
web.run_app(app, host="0.0.0.0", port=5000)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from rubigram.types import Update, InlineMessage
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
def command(commands: Union[str, list[str]], prefixe: str = "/"):
|
|
5
|
+
def filter(message: Update):
|
|
6
|
+
if isinstance(message, Update) and message.type == "NewMessage" and message.new_message.text:
|
|
7
|
+
text = message.new_message.text
|
|
8
|
+
COMMANDS = commands if isinstance(commands, list) else [commands]
|
|
9
|
+
for cmd in COMMANDS:
|
|
10
|
+
if text.lower().startswith(prefixe + cmd):
|
|
11
|
+
return True
|
|
12
|
+
return False
|
|
13
|
+
return filter
|
|
14
|
+
|
|
15
|
+
def button(id: Union[str, list[str]]):
|
|
16
|
+
def filter(message: InlineMessage):
|
|
17
|
+
if isinstance(message, InlineMessage):
|
|
18
|
+
button_id = message.aux_data.button_id
|
|
19
|
+
ID = id if isinstance(id, list) else [id]
|
|
20
|
+
for i in ID:
|
|
21
|
+
if button_id == i:
|
|
22
|
+
return True
|
|
23
|
+
return False
|
|
24
|
+
return filter
|
|
25
|
+
|
|
26
|
+
def chat(chat_id: Union[str, list[str]]):
|
|
27
|
+
def filter(message: Union[Update, InlineMessage]):
|
|
28
|
+
chat_ids = chat_id if isinstance(chat_id, list) else [chat_id]
|
|
29
|
+
if isinstance(message, Update) or isinstance(message, InlineMessage):
|
|
30
|
+
return message.chat_id in chat_ids
|
|
31
|
+
return False
|
|
32
|
+
return filter
|
|
33
|
+
|
|
34
|
+
def text():
|
|
35
|
+
def filter(message: Update):
|
|
36
|
+
if isinstance(message, Update) and message.type == "NewMessage":
|
|
37
|
+
return bool(message.new_message.text)
|
|
38
|
+
return False
|
|
39
|
+
return filter
|
|
40
|
+
|
|
41
|
+
def file():
|
|
42
|
+
def filter(message: Update):
|
|
43
|
+
if isinstance(message, Update) and message.type == "NewMessage":
|
|
44
|
+
return bool(message.new_message.file)
|
|
45
|
+
return False
|
|
46
|
+
return filter
|
|
47
|
+
|
|
48
|
+
def private():
|
|
49
|
+
def filter(message: Update):
|
|
50
|
+
if isinstance(message, Update) and message.type == "NewMessage":
|
|
51
|
+
return message.new_message.sender_type in ["User", "Bot"]
|
|
52
|
+
return False
|
|
53
|
+
return filter
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
from rubigram.network import NetWork
|
|
2
|
+
from typing import Literal, Optional
|
|
3
|
+
from rubigram.types import Bot, Chat, Update, Keypad, MessageId
|
|
4
|
+
|
|
5
|
+
class Method(NetWork):
|
|
6
|
+
def __init__(self, token: str):
|
|
7
|
+
super().__init__(token)
|
|
8
|
+
|
|
9
|
+
async def get_me(self) -> "Bot":
|
|
10
|
+
response = await self.request("getMe", {})
|
|
11
|
+
return Bot.read(response["data"]["bot"])
|
|
12
|
+
|
|
13
|
+
async def get_chat(self, chat_id: str) -> "Chat":
|
|
14
|
+
response = await self.request("getChat", {"chat_id": chat_id})
|
|
15
|
+
return Chat.read(response["data"]["chat"])
|
|
16
|
+
|
|
17
|
+
async def get_update(self, limit: int = 1, offset_id: Optional[int] = None) -> list[Update]:
|
|
18
|
+
response = await self.request("getUpdates", {"limit": limit, "offset_id": offset_id})
|
|
19
|
+
return [Update.read(update) for update in response["data"]["updates"]]
|
|
20
|
+
|
|
21
|
+
async def get_file(self, file_id: str) -> str:
|
|
22
|
+
response = await self.request("getFile", {"file_id": file_id})
|
|
23
|
+
return response["data"]["download_url"]
|
|
24
|
+
|
|
25
|
+
async def set_command(self, command: list):
|
|
26
|
+
response = await self.request("setCommands", {"bot_commands": command})
|
|
27
|
+
return response
|
|
28
|
+
|
|
29
|
+
async def update_bot_endpoint(self, url: str, type: Literal["ReceiveUpdate", "ReceiveInlineMessage", "ReceiveQuery", "GetSelectionItem", "SearchSelectionItems"]):
|
|
30
|
+
response = await self.request("updateBotEndpoints", {"url": url, "type": type})
|
|
31
|
+
return response
|
|
32
|
+
|
|
33
|
+
async def request_send_file(self, type: str):
|
|
34
|
+
response = await self.request("requestSendFile", {"type": type})
|
|
35
|
+
return response["data"]["upload_url"]
|
|
36
|
+
|
|
37
|
+
async def upload_file(self, path: str, name: str, type: str):
|
|
38
|
+
upload_url = await self.request_send_file(type)
|
|
39
|
+
response = await self.request_upload_file(upload_url, path, name)
|
|
40
|
+
return response
|
|
41
|
+
|
|
42
|
+
async def forward_message(self, from_chat_id: str, message_id: str, to_chat_id: str, disable_notification: bool = False) -> "MessageId":
|
|
43
|
+
data = {"from_chat_id": from_chat_id, "message_id": message_id, "to_chat_id": to_chat_id, "disable_notification": disable_notification}
|
|
44
|
+
response = await self.request("forwardMessage", data)
|
|
45
|
+
return MessageId.read(response["data"])
|
|
46
|
+
|
|
47
|
+
async def delete_message(self, chat_id: str, message_id: str):
|
|
48
|
+
await self.request("deleteMessage", {"chat_id": chat_id, "message_id": message_id})
|
|
49
|
+
|
|
50
|
+
async def remove_chat_keypad(self, chat_id: str):
|
|
51
|
+
await self.request("editChatKeypad", {"chat_id": chat_id, "chat_keypad_type": "Remove"})
|
|
52
|
+
|
|
53
|
+
async def edit_chat_keypad(self, chat_id: str, chat_keypad):
|
|
54
|
+
await self.request("editChatKeypad", {"chat_id": chat_id, "chat_keypad_type": "New", "chat_keypad": chat_keypad})
|
|
55
|
+
|
|
56
|
+
async def edit_message_keypad(self, chat_id: str, message_id: str, inline_keypad):
|
|
57
|
+
await self.request("editMessageKeypad", {"chat_id": chat_id, "message_id": message_id, "inline_keypad": inline_keypad})
|
|
58
|
+
|
|
59
|
+
async def edit_message_text(self, chat_id: str, message_id: str, text: str):
|
|
60
|
+
await self.request("editMessageText", {"chat_id": chat_id, "message_id": message_id, "text": text})
|
|
61
|
+
|
|
62
|
+
async def send_message(
|
|
63
|
+
self,
|
|
64
|
+
chat_id: str,
|
|
65
|
+
text: str,
|
|
66
|
+
chat_keypad: Keypad = None,
|
|
67
|
+
inline_keypad: Keypad= None,
|
|
68
|
+
chat_keypad_type: Literal["New", "Remove"] = None,
|
|
69
|
+
disable_notification: bool = None,
|
|
70
|
+
reply_to_message_id = None
|
|
71
|
+
) -> "MessageId":
|
|
72
|
+
data = {
|
|
73
|
+
"chat_id": chat_id,
|
|
74
|
+
"text": text,
|
|
75
|
+
"chat_keypad": chat_keypad._dict() if chat_keypad else None,
|
|
76
|
+
"inline_keypad": inline_keypad._dict() if inline_keypad else None,
|
|
77
|
+
"chat_keypad_type": chat_keypad_type,
|
|
78
|
+
"disable_notification": disable_notification,
|
|
79
|
+
"reply_to_message_id": reply_to_message_id
|
|
80
|
+
}
|
|
81
|
+
response = await self.request("sendMessage", data)
|
|
82
|
+
return MessageId.read(response["data"])
|
|
83
|
+
|
|
84
|
+
async def send_poll(
|
|
85
|
+
self,
|
|
86
|
+
chat_id: str,
|
|
87
|
+
question: str,
|
|
88
|
+
options: list[str],
|
|
89
|
+
chat_keypad: Keypad = None,
|
|
90
|
+
inline_keypad: Keypad = None,
|
|
91
|
+
disable_notification: bool = False,
|
|
92
|
+
reply_to_message_id: str = None,
|
|
93
|
+
chat_keypad_type: Literal["New", "Remove"] = None
|
|
94
|
+
) -> "MessageId":
|
|
95
|
+
data = {
|
|
96
|
+
"chat_id": chat_id,
|
|
97
|
+
"question": question,
|
|
98
|
+
"options": options,
|
|
99
|
+
"chat_keypad": chat_keypad._dict() if chat_keypad else None,
|
|
100
|
+
"inline_keypad": inline_keypad._dict() if inline_keypad else None,
|
|
101
|
+
"disable_notification": disable_notification,
|
|
102
|
+
"reply_to_message_id": reply_to_message_id,
|
|
103
|
+
"chat_keypad_type": chat_keypad_type
|
|
104
|
+
}
|
|
105
|
+
response = await self.request("sendPoll", data)
|
|
106
|
+
return MessageId.read(response["data"])
|
|
107
|
+
|
|
108
|
+
async def send_location(
|
|
109
|
+
self,
|
|
110
|
+
chat_id: str,
|
|
111
|
+
latitude: str,
|
|
112
|
+
longitude: str,
|
|
113
|
+
chat_keypad: Keypad = None,
|
|
114
|
+
inline_keypad: Keypad = None,
|
|
115
|
+
disable_notification: bool = False,
|
|
116
|
+
reply_to_message_id: str = None,
|
|
117
|
+
chat_keypad_type: Literal["New", "Remove"] = None
|
|
118
|
+
) -> "MessageId":
|
|
119
|
+
data = {
|
|
120
|
+
"chat_id": chat_id,
|
|
121
|
+
"latitude": latitude,
|
|
122
|
+
"longitude": longitude,
|
|
123
|
+
"chat_keypad": chat_keypad._dict() if chat_keypad else None,
|
|
124
|
+
"inline_keypad": inline_keypad._dict() if inline_keypad else None,
|
|
125
|
+
"disable_notification": disable_notification,
|
|
126
|
+
"reply_to_message_id": reply_to_message_id,
|
|
127
|
+
"chat_keypad_type": chat_keypad_type
|
|
128
|
+
}
|
|
129
|
+
response = await self.request("sendLocation", data)
|
|
130
|
+
return MessageId.read(response["data"])
|
|
131
|
+
|
|
132
|
+
async def send_contact(
|
|
133
|
+
self,
|
|
134
|
+
chat_id: str,
|
|
135
|
+
first_name: str,
|
|
136
|
+
last_name: str,
|
|
137
|
+
phone_number: str,
|
|
138
|
+
chat_keypad: Keypad = None,
|
|
139
|
+
inline_keypad: Keypad = None,
|
|
140
|
+
disable_notification: bool = False,
|
|
141
|
+
reply_to_message_id: str = None,
|
|
142
|
+
chat_keypad_type: Literal["New", "Remove"] = None
|
|
143
|
+
) -> "MessageId":
|
|
144
|
+
data = {
|
|
145
|
+
"chat_id": chat_id,
|
|
146
|
+
"first_name": first_name,
|
|
147
|
+
"last_name": last_name,
|
|
148
|
+
"phone_number": phone_number,
|
|
149
|
+
"chat_keypad": chat_keypad._dict() if chat_keypad else None,
|
|
150
|
+
"inline_keypad": inline_keypad._dict() if inline_keypad else None,
|
|
151
|
+
"disable_notification": disable_notification,
|
|
152
|
+
"reply_to_message_id": reply_to_message_id,
|
|
153
|
+
"chat_keypad_type": chat_keypad_type
|
|
154
|
+
}
|
|
155
|
+
response = await self.request("sendContact", data)
|
|
156
|
+
return MessageId.read(response["data"])
|
|
157
|
+
|
|
158
|
+
async def send_sticker(
|
|
159
|
+
self,
|
|
160
|
+
chat_id: str,
|
|
161
|
+
sticker_id: str,
|
|
162
|
+
chat_keypad: Keypad = None,
|
|
163
|
+
inline_keypad: Keypad = None,
|
|
164
|
+
disable_notification: bool = False,
|
|
165
|
+
reply_to_message_id: str = None,
|
|
166
|
+
chat_keypad_type: Literal["New", "Remove"] = None,
|
|
167
|
+
) -> "MessageId":
|
|
168
|
+
data = {
|
|
169
|
+
"chat_id": chat_id,
|
|
170
|
+
"sticker_id": sticker_id,
|
|
171
|
+
"chat_keypad": chat_keypad._dict() if chat_keypad else None,
|
|
172
|
+
"inline_keypad": inline_keypad._dict() if inline_keypad else None,
|
|
173
|
+
"disable_notification": disable_notification,
|
|
174
|
+
"reply_to_message_id": reply_to_message_id,
|
|
175
|
+
"chat_keypad_type": chat_keypad_type
|
|
176
|
+
}
|
|
177
|
+
response = await self.request("sendSticker", data)
|
|
178
|
+
return MessageId.read(response["data"])
|
|
179
|
+
|
|
180
|
+
async def send_file(
|
|
181
|
+
self,
|
|
182
|
+
chat_id: str,
|
|
183
|
+
path: str,
|
|
184
|
+
file_name: str,
|
|
185
|
+
type: Literal["File", "Image", "Voice", "Music", "Gif", "Video"] = "File",
|
|
186
|
+
chat_keypad: Keypad = None,
|
|
187
|
+
inline_keypad: Keypad = None,
|
|
188
|
+
disable_notification: bool = False,
|
|
189
|
+
reply_to_message_id: str = None,
|
|
190
|
+
chat_keypad_type: Literal["New", "Remove"] = None,
|
|
191
|
+
) -> "MessageId":
|
|
192
|
+
file_id = await self.upload_file(path, file_name, type)
|
|
193
|
+
data = {
|
|
194
|
+
"chat_id": chat_id,
|
|
195
|
+
"file_id": file_id,
|
|
196
|
+
"chat_keypad": chat_keypad._dict() if chat_keypad else None,
|
|
197
|
+
"inline_keypad": inline_keypad._dict() if inline_keypad else None,
|
|
198
|
+
"disable_notification": disable_notification,
|
|
199
|
+
"reply_to_message_id": reply_to_message_id,
|
|
200
|
+
"chat_keypad_type": chat_keypad_type,
|
|
201
|
+
}
|
|
202
|
+
response = await self.request("sendFile", data)
|
|
203
|
+
return MessageId.read(response["data"])
|
|
204
|
+
|
|
205
|
+
async def download_file(self, file_id: str, file_name: str):
|
|
206
|
+
download_url = await self.get_file(file_id)
|
|
207
|
+
response = await self.request_download_file(download_url, file_name)
|
|
208
|
+
return response
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from aiohttp import ClientSession, FormData
|
|
2
|
+
import aiofiles
|
|
3
|
+
|
|
4
|
+
class NetWork:
|
|
5
|
+
def __init__(self, token: str):
|
|
6
|
+
self.token = token
|
|
7
|
+
self.api = f"https://botapi.rubika.ir/v3/{self.token}/"
|
|
8
|
+
|
|
9
|
+
async def request(self, method: str, json: dict) -> dict:
|
|
10
|
+
async with ClientSession() as session:
|
|
11
|
+
async with session.post(self.api + method, json=json) as response:
|
|
12
|
+
response.raise_for_status()
|
|
13
|
+
return await response.json()
|
|
14
|
+
|
|
15
|
+
async def request_upload_file(self, url: str, path: str, name: str) -> str:
|
|
16
|
+
form = FormData()
|
|
17
|
+
form.add_field("file", open(path, "rb"), filename=name, content_type="application/octet-stream")
|
|
18
|
+
async with ClientSession() as session:
|
|
19
|
+
async with session.post(url, data=form) as response:
|
|
20
|
+
response.raise_for_status()
|
|
21
|
+
result = await response.json()
|
|
22
|
+
return result["data"]["file_id"]
|
|
23
|
+
|
|
24
|
+
async def request_download_file(self, url: str, name: str):
|
|
25
|
+
async with ClientSession() as session:
|
|
26
|
+
async with session.get(url) as response:
|
|
27
|
+
response.raise_for_status()
|
|
28
|
+
async with aiofiles.open(name, mode="wb") as file:
|
|
29
|
+
await file.write(await response.read())
|
|
30
|
+
return {"status": True, "file": name}
|
|
@@ -200,6 +200,7 @@ class MessageId:
|
|
|
200
200
|
message_id = data.get("message_id"),
|
|
201
201
|
file_id = data.get("file_id")
|
|
202
202
|
)
|
|
203
|
+
|
|
203
204
|
|
|
204
205
|
@dataclass
|
|
205
206
|
class PollStatus:
|
|
@@ -270,14 +271,14 @@ class Poll:
|
|
|
270
271
|
@dataclass
|
|
271
272
|
class ContactMessage:
|
|
272
273
|
phone_number: Optional[str] = None
|
|
273
|
-
first_name: Optional[
|
|
274
|
+
first_name: Optional[str] = None
|
|
274
275
|
last_name: Optional[str] = None
|
|
275
276
|
|
|
276
277
|
@classmethod
|
|
277
278
|
def read(cls, data: dict[str, Any]) -> "ContactMessage":
|
|
278
279
|
return cls(
|
|
279
280
|
phone_number = data.get("phone_number"),
|
|
280
|
-
first_name =
|
|
281
|
+
first_name = data.get("first_name"),
|
|
281
282
|
last_name = data.get("last_name")
|
|
282
283
|
)
|
|
283
284
|
|
|
@@ -458,7 +459,7 @@ class Update:
|
|
|
458
459
|
type = data["type"],
|
|
459
460
|
chat_id = data["chat_id"],
|
|
460
461
|
removed_message_id = data.get("removed_message_id"),
|
|
461
|
-
new_message = Message.read(data["new_message"]),
|
|
462
|
+
new_message = Message.read(data["new_message"]) if "new_message" in data else None,
|
|
462
463
|
updated_message = Message.read(data["updated_message"]) if "updated_message" in data else None,
|
|
463
464
|
updated_payment = PaymentStatus.read(data["updated_payment"]) if "updated_payment" in data else None
|
|
464
465
|
)
|
|
@@ -467,4 +468,7 @@ class Update:
|
|
|
467
468
|
return await self.client.send_message(self.chat_id, text, reply_to_message_id=self.new_message.message_id)
|
|
468
469
|
|
|
469
470
|
async def reply_file(self, path: str, file_name: str, type: Literal["File", "Image", "Voice", "Music", "Gif", "Video"] = "File") -> "MessageId":
|
|
470
|
-
return await self.client.send_file(self.chat_id, path, file_name, type, reply_to_message_id=self.new_message.message_id)
|
|
471
|
+
return await self.client.send_file(self.chat_id, path, file_name, type, reply_to_message_id=self.new_message.message_id)
|
|
472
|
+
|
|
473
|
+
async def download(self, file_name: str):
|
|
474
|
+
return await self.client.download_file(self.new_message.file.file_id, file_name)
|
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
from rubigram.types import Update, MessageId, InlineMessage, Keypad, Chat, Bot
|
|
2
|
-
from aiohttp import ClientSession, FormData, web
|
|
3
|
-
from typing import Literal, Optional
|
|
4
|
-
import aiofiles
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Client:
|
|
8
|
-
def __init__(self, token: str):
|
|
9
|
-
self.token = token
|
|
10
|
-
self.messages_handler = []
|
|
11
|
-
self.api = f"https://botapi.rubika.ir/v3/{self.token}"
|
|
12
|
-
|
|
13
|
-
async def request(self, method: str, data: dict):
|
|
14
|
-
async with ClientSession() as session:
|
|
15
|
-
async with session.post(f"{self.api}/{method}", json=data) as response:
|
|
16
|
-
response.raise_for_status()
|
|
17
|
-
return await response.json()
|
|
18
|
-
|
|
19
|
-
def on_message(self, *filters):
|
|
20
|
-
def decorator(func):
|
|
21
|
-
async def wrapped(client, update):
|
|
22
|
-
if all(f(update) for f in filters):
|
|
23
|
-
await func(client, update)
|
|
24
|
-
self.messages_handler.append(wrapped)
|
|
25
|
-
return func
|
|
26
|
-
return decorator
|
|
27
|
-
|
|
28
|
-
async def update(self, data: dict):
|
|
29
|
-
event = Update.read(data["update"], self) if data.get("update") else InlineMessage.read(data["inline_message"])
|
|
30
|
-
for handler in self.messages_handler:
|
|
31
|
-
await handler(self, event)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
async def get_me(self) -> "Bot":
|
|
35
|
-
response = await self.request("getMe", {})
|
|
36
|
-
return Bot.read(response["data"]["bot"])
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
async def get_chat(self, chat_id: str) -> "Chat":
|
|
40
|
-
response = await self.request("getChat", {"chat_id": chat_id})
|
|
41
|
-
return Chat.read(response["data"]["chat"])
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
async def get_updates(self, limit: int = 1, offset_id: str = None) -> list["Update"]:
|
|
45
|
-
response = await self.request("getUpdates", {"limit": limit, "offset_id": offset_id})
|
|
46
|
-
updates = [update for update in response["data"]["updates"]]
|
|
47
|
-
return [Update.read(update) for update in updates]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
async def set_command(self, commands: list):
|
|
51
|
-
response = await self.request("setCommands", {"bot_commands": commands})
|
|
52
|
-
return response
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
async def update_bot_endpoint(
|
|
56
|
-
self,
|
|
57
|
-
url: str,
|
|
58
|
-
type: Literal["ReceiveUpdate", "ReceiveInlineMessage", "ReceiveQuery", "GetSelectionItem", "SearchSelectionItems"]
|
|
59
|
-
):
|
|
60
|
-
response = await self.request("updateBotEndpoints", {"url": url, "type": type})
|
|
61
|
-
return response
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
async def send_message(
|
|
65
|
-
self,
|
|
66
|
-
chat_id: str,
|
|
67
|
-
text: str,
|
|
68
|
-
chat_keypad : Optional[Keypad] = None,
|
|
69
|
-
inline_keypad: Optional[Keypad] = None,
|
|
70
|
-
chat_keypad_type: Literal["New", "Remove"] = None,
|
|
71
|
-
disable_notification: bool = None,
|
|
72
|
-
reply_to_message_id = None
|
|
73
|
-
) -> "MessageId":
|
|
74
|
-
data = {
|
|
75
|
-
"chat_id": chat_id,
|
|
76
|
-
"text": text,
|
|
77
|
-
"chat_keypad": chat_keypad._dict() if chat_keypad else None,
|
|
78
|
-
"inline_keypad": inline_keypad._dict() if inline_keypad else None,
|
|
79
|
-
"chat_keypad_type": chat_keypad_type,
|
|
80
|
-
"disable_notification": disable_notification,
|
|
81
|
-
"reply_to_message_id": reply_to_message_id
|
|
82
|
-
}
|
|
83
|
-
response = await self.request("sendMessage", data)
|
|
84
|
-
return MessageId.read(response["data"])
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
async def send_poll(
|
|
88
|
-
self,
|
|
89
|
-
chat_id: str,
|
|
90
|
-
question: str,
|
|
91
|
-
options: list[str],
|
|
92
|
-
chat_keypad: Keypad = None,
|
|
93
|
-
inline_keypad: Keypad = None,
|
|
94
|
-
disable_notification: bool = False,
|
|
95
|
-
reply_to_message_id: str = None,
|
|
96
|
-
chat_keypad_type: Literal[None, "New", "Remove"] = None
|
|
97
|
-
) -> "MessageId":
|
|
98
|
-
data = {
|
|
99
|
-
"chat_id": chat_id,
|
|
100
|
-
"question": question,
|
|
101
|
-
"options": options,
|
|
102
|
-
"chat_keypad": chat_keypad,
|
|
103
|
-
"inline_keypad": inline_keypad,
|
|
104
|
-
"disable_notification": disable_notification,
|
|
105
|
-
"reply_to_message_id": reply_to_message_id,
|
|
106
|
-
"chat_keypad_type": chat_keypad_type
|
|
107
|
-
}
|
|
108
|
-
response = await self.request("sendPoll", data)
|
|
109
|
-
return MessageId.read(response["data"])
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
async def send_location(
|
|
113
|
-
self,
|
|
114
|
-
chat_id: str,
|
|
115
|
-
latitude: str,
|
|
116
|
-
longitude: str,
|
|
117
|
-
chat_keypad: Keypad = None,
|
|
118
|
-
inline_keypad: Keypad = None,
|
|
119
|
-
disable_notification: bool = False,
|
|
120
|
-
reply_to_message_id: str = None,
|
|
121
|
-
chat_keypad_type: Literal[None, "New", "Remove"] = None
|
|
122
|
-
) -> "MessageId":
|
|
123
|
-
data = {
|
|
124
|
-
"chat_id": chat_id,
|
|
125
|
-
"latitude": latitude,
|
|
126
|
-
"longitude": longitude,
|
|
127
|
-
"chat_keypad": chat_keypad,
|
|
128
|
-
"inline_keypad": inline_keypad,
|
|
129
|
-
"disable_notification": disable_notification,
|
|
130
|
-
"reply_to_message_id": reply_to_message_id,
|
|
131
|
-
"chat_keypad_type": chat_keypad_type
|
|
132
|
-
}
|
|
133
|
-
response = await self.request("sendLocation", data)
|
|
134
|
-
return MessageId.read(response["data"])
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
async def send_contact(
|
|
138
|
-
self,
|
|
139
|
-
chat_id: str,
|
|
140
|
-
first_name: str,
|
|
141
|
-
last_name: str,
|
|
142
|
-
phone_number: str,
|
|
143
|
-
chat_keypad: Keypad = None,
|
|
144
|
-
inline_keypad: Keypad = None,
|
|
145
|
-
disable_notification: bool = False,
|
|
146
|
-
reply_to_message_id: str = None,
|
|
147
|
-
chat_keypad_type: Literal[None, "New", "Remove"] = None
|
|
148
|
-
) -> "MessageId":
|
|
149
|
-
data = {
|
|
150
|
-
"chat_id": chat_id,
|
|
151
|
-
"first_name": first_name,
|
|
152
|
-
"last_name": last_name,
|
|
153
|
-
"phone_number": phone_number,
|
|
154
|
-
"chat_keypad": chat_keypad,
|
|
155
|
-
"inline_keypad": inline_keypad,
|
|
156
|
-
"disable_notification": disable_notification,
|
|
157
|
-
"reply_to_message_id": reply_to_message_id,
|
|
158
|
-
"chat_keypad_type": chat_keypad_type
|
|
159
|
-
}
|
|
160
|
-
response = await self.request("sendContact", data)
|
|
161
|
-
return MessageId.read(response["data"])
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
async def send_sticker(
|
|
165
|
-
self,
|
|
166
|
-
chat_id: str,
|
|
167
|
-
sticker_id: str,
|
|
168
|
-
chat_keypad: Keypad = None,
|
|
169
|
-
inline_keypad: Keypad = None,
|
|
170
|
-
disable_notification: bool = False,
|
|
171
|
-
reply_to_message_id: str = None,
|
|
172
|
-
chat_keypad_type: Literal[None, "New", "Remove"] = None,
|
|
173
|
-
) -> "MessageId":
|
|
174
|
-
data = {
|
|
175
|
-
"chat_id": chat_id,
|
|
176
|
-
"sticker_id": sticker_id,
|
|
177
|
-
"chat_keypad": chat_keypad,
|
|
178
|
-
"disable_notification": disable_notification,
|
|
179
|
-
"inline_keypad": inline_keypad,
|
|
180
|
-
"reply_to_message_id": reply_to_message_id,
|
|
181
|
-
"chat_keypad_type": chat_keypad_type
|
|
182
|
-
}
|
|
183
|
-
response = await self.request("sendSticker", data)
|
|
184
|
-
return MessageId.read(response["data"])
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
async def forward_message(
|
|
188
|
-
self,
|
|
189
|
-
from_chat_id: str,
|
|
190
|
-
message_id: str,
|
|
191
|
-
to_chat_id: str,
|
|
192
|
-
disable_notification: bool = False
|
|
193
|
-
) -> "MessageId":
|
|
194
|
-
data = {
|
|
195
|
-
"from_chat_id": from_chat_id,
|
|
196
|
-
"message_id": message_id,
|
|
197
|
-
"to_chat_id": to_chat_id,
|
|
198
|
-
"disable_notification": disable_notification
|
|
199
|
-
}
|
|
200
|
-
response = await self.request("forwardMessage", data)
|
|
201
|
-
return MessageId.read(response["data"])
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
async def edit_message_text(
|
|
205
|
-
self,
|
|
206
|
-
chat_id: str,
|
|
207
|
-
message_id: str,
|
|
208
|
-
text: str
|
|
209
|
-
) -> None:
|
|
210
|
-
data = {"chat_id": chat_id, "message_id": message_id, "text": text}
|
|
211
|
-
await self.request("editMessageText", data)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
async def edit_message_keypad(
|
|
215
|
-
self,
|
|
216
|
-
chat_id: str,
|
|
217
|
-
message_id: str,
|
|
218
|
-
inline_keypad: Keypad
|
|
219
|
-
) -> None:
|
|
220
|
-
data = {"chat_id": chat_id, "message_id": message_id, "inline_keypad": inline_keypad}
|
|
221
|
-
await self.request("editMessageKeypad", data)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
async def edit_chat_keypad(
|
|
225
|
-
self,
|
|
226
|
-
chat_id: str,
|
|
227
|
-
chat_keypad: Keypad
|
|
228
|
-
) -> None:
|
|
229
|
-
data = {"chat_id": chat_id, "chat_keypad_type": "New", "chat_keypad": chat_keypad}
|
|
230
|
-
await self.request("editChatKeypad", data)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
async def remove_chat_keypad(
|
|
234
|
-
self,
|
|
235
|
-
chat_id: str
|
|
236
|
-
) -> None:
|
|
237
|
-
data = {"chat_id": chat_id, "chat_keypad_type": "Remove"}
|
|
238
|
-
await self.request("editChatKeypad", data)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
async def delete_message(
|
|
242
|
-
self,
|
|
243
|
-
chat_id: str,
|
|
244
|
-
message_id: str
|
|
245
|
-
) -> None:
|
|
246
|
-
data = {"chat_id": chat_id, "message_id": message_id}
|
|
247
|
-
await self.request("deleteMessage", data)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
async def get_file(self, file_id: str) -> str:
|
|
251
|
-
response = await self.request("getFile", {"file_id": file_id})
|
|
252
|
-
return response["data"]["download_url"]
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
async def request_send_file(self, type: Literal["File", "Image", "Voice", "Music", "Gif", "Video"]) -> str:
|
|
256
|
-
response = await self.request("requestSendFile", {"type": type})
|
|
257
|
-
return response["data"]["upload_url"]
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
async def upload_file(self, path: str, file_name: str, type: Literal["File", "Image", "Voice", "Music", "Gif", "Video"]) -> str:
|
|
261
|
-
upload_url = await self.request_send_file(type)
|
|
262
|
-
form = FormData()
|
|
263
|
-
form.add_field("file", open(path, "rb"), filename=file_name, content_type="application/octet-stream")
|
|
264
|
-
async with ClientSession() as session:
|
|
265
|
-
async with session.post(upload_url, data=form) as response:
|
|
266
|
-
result = await response.json()
|
|
267
|
-
return result["data"]["file_id"]
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
async def send_file(
|
|
271
|
-
self,
|
|
272
|
-
chat_id: str,
|
|
273
|
-
path: str,
|
|
274
|
-
file_name: str,
|
|
275
|
-
type: Literal["File", "Image", "Voice", "Music", "Gif", "Video"] = "File",
|
|
276
|
-
chat_keypad = None,
|
|
277
|
-
inline_keypad = None,
|
|
278
|
-
disable_notification: bool = False,
|
|
279
|
-
reply_to_message_id: str = None,
|
|
280
|
-
chat_keypad_type: Literal["New", "Remove"] = None,
|
|
281
|
-
) -> str:
|
|
282
|
-
file_id = await self.upload_file(path, file_name, type)
|
|
283
|
-
data = {
|
|
284
|
-
"chat_id": chat_id,
|
|
285
|
-
"file_id": file_id,
|
|
286
|
-
"chat_keypad": chat_keypad,
|
|
287
|
-
"disable_notification": disable_notification,
|
|
288
|
-
"inline_keypad": inline_keypad,
|
|
289
|
-
"reply_to_message_id": reply_to_message_id,
|
|
290
|
-
"chat_keypad_type": chat_keypad_type,
|
|
291
|
-
}
|
|
292
|
-
response = await self.request("sendFile", data)
|
|
293
|
-
return MessageId.read(response["data"])
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
async def download_file(self, file_id: str, file_name: str):
|
|
297
|
-
download_url = await self.get_file(file_id)
|
|
298
|
-
async with ClientSession() as session:
|
|
299
|
-
async with session.get(download_url) as response:
|
|
300
|
-
if response.status == 200:
|
|
301
|
-
async with aiofiles.open(file_name, "wb") as file:
|
|
302
|
-
await file.write(await response.read())
|
|
303
|
-
return {"status": "OK", "file": file_name}
|
|
304
|
-
raise Exception(f"Download Error | status_code : {response.status}")
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def run(self):
|
|
308
|
-
routes = web.RouteTableDef()
|
|
309
|
-
@routes.post("/receiveUpdate")
|
|
310
|
-
@routes.post("/receiveInlineMessage")
|
|
311
|
-
async def webhook(request):
|
|
312
|
-
data = await request.json()
|
|
313
|
-
await self.update(data)
|
|
314
|
-
return web.json_response({"status": "ok"})
|
|
315
|
-
app = web.Application()
|
|
316
|
-
app.add_routes(routes)
|
|
317
|
-
web.run_app(app, host="0.0.0.0", port=8000)
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
from rubigram.types import Update, InlineMessage
|
|
2
|
-
from typing import Union
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class filter:
|
|
6
|
-
@staticmethod
|
|
7
|
-
def command(command: Union[str, list[str]], prefixes: Union[str, list[str]] = "/"):
|
|
8
|
-
def inner(update: Update):
|
|
9
|
-
if isinstance(update, Update) and update.new_message and update.new_message.text:
|
|
10
|
-
message = update.new_message
|
|
11
|
-
commands = command if isinstance(command, list) else [command]
|
|
12
|
-
commands = [c.lower() for c in commands]
|
|
13
|
-
prefix_list = [] if prefixes is None else prefixes
|
|
14
|
-
prefix_list = prefix_list if isinstance(prefix_list, list) else [prefix_list]
|
|
15
|
-
for prefix in prefix_list:
|
|
16
|
-
if message.text.startswith(prefix) and commands:
|
|
17
|
-
return message.text[len(prefix):].split()[0].lower() in commands
|
|
18
|
-
return False
|
|
19
|
-
return False
|
|
20
|
-
return inner
|
|
21
|
-
|
|
22
|
-
@staticmethod
|
|
23
|
-
def text():
|
|
24
|
-
def inner(update: Update):
|
|
25
|
-
if isinstance(update, Update) and update.new_message:
|
|
26
|
-
return update.new_message.text is not None
|
|
27
|
-
return False
|
|
28
|
-
return inner
|
|
29
|
-
|
|
30
|
-
@staticmethod
|
|
31
|
-
def private():
|
|
32
|
-
def inner(update: Update):
|
|
33
|
-
if isinstance(update, Update) and update.new_message:
|
|
34
|
-
return update.new_message.sender_type == "User"
|
|
35
|
-
return False
|
|
36
|
-
return inner
|
|
37
|
-
|
|
38
|
-
@staticmethod
|
|
39
|
-
def chat(chat_id: str):
|
|
40
|
-
def inner(update: Update):
|
|
41
|
-
return getattr(update, "chat_id", None) == chat_id
|
|
42
|
-
return inner
|
|
43
|
-
|
|
44
|
-
@staticmethod
|
|
45
|
-
def file():
|
|
46
|
-
def inner(update: Update):
|
|
47
|
-
if isinstance(update, Update) and update.new_message:
|
|
48
|
-
return update.new_message.file is not None
|
|
49
|
-
return False
|
|
50
|
-
return inner
|
|
51
|
-
|
|
52
|
-
@staticmethod
|
|
53
|
-
def button(id: str):
|
|
54
|
-
def inner(update: InlineMessage):
|
|
55
|
-
if isinstance(update, InlineMessage):
|
|
56
|
-
return update.aux_data.button_id == id
|
|
57
|
-
return False
|
|
58
|
-
return inner
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|