from secrets import choice
from traceback import format_exc
from pyrogram import enums, filters
from pyrogram.enums import ChatMemberStatus as CMS
from pyrogram.errors import RPCError
from pyrogram.types import CallbackQuery, Message
from Powers import LOGGER
from Powers.bot_class import Gojo
from Powers.database.notes_db import Notes, NotesSettings
from Powers.utils.cmd_senders import send_cmd
from Powers.utils.custom_filters import admin_filter, command, owner_filter
from Powers.utils.kbhelpers import ikb
from Powers.utils.msg_types import Types, get_note_type
from Powers.utils.string import (build_keyboard,
escape_mentions_using_curly_brackets,
parse_button)
# Initialise
db = Notes()
db_settings = NotesSettings()
@Gojo.on_message(command("save") & admin_filter & ~filters.bot)
async def save_note(_, m: Message):
existing_notes = {i[0] for i in db.get_all_notes(m.chat.id)}
name, text, data_type, content = await get_note_type(m)
total_notes = db.get_all_notes(m.chat.id)
if len(total_notes) >= 1000:
await m.reply_text(
"Only 1000 Notes are allowed per chat!\nTo add more Notes, remove the existing ones.",
)
return
if not name:
await m.reply_text(
f"{m.text}
\n\nError: You must give a name for this note!",
)
return
note_name = name.lower()
if note_name in existing_notes:
await m.reply_text(f"This note ({note_name}) already exists!")
return
if note_name.startswith("<") or note_name.startswith(">"):
await m.reply_text("Cannot save a note which starts with '<' or '>'")
return
if not m.reply_to_message and data_type == Types.TEXT and len(m.text.split()) < 3:
await m.reply_text(f"{m.text}
\n\nError: There is no text in here!")
return
if not data_type:
await m.reply_text(
f"{m.text}
\n\nError: There is no data in here!",
)
return
db.save_note(m.chat.id, note_name, text, data_type, content)
await m.reply_text(
f"Saved note {note_name}
!\nGet it with /get {note_name}
or #{note_name}
",
)
return
async def get_note_func(c: Gojo, m: Message, note_name, priv_notes_status):
"""Get the note in normal mode, with parsing enabled."""
reply_text = m.reply_to_message.reply_text if m.reply_to_message else m.reply_text
reply_msg_id = m.reply_to_message_id if m.reply_to_message else m.id
if m and not m.from_user:
return
if priv_notes_status:
note_hash = next(i[1] for i in db.get_all_notes(m.chat.id) if i[0] == note_name)
await reply_text(
f"Click on the button to get the note {note_name}
",
reply_markup=ikb(
[
[
(
"Click Me!",
f"https://t.me/{c.me.username}?start=note_{m.chat.id}_{note_hash}",
"url",
),
],
],
),
)
return
getnotes = db.get_note(m.chat.id, note_name)
msgtype = getnotes["msgtype"]
if not msgtype:
await reply_text("Error: Cannot find a type for this note!!")
return
try:
# support for random notes texts
splitter = "%%%"
note_reply = getnotes["note_value"].split(splitter)
note_reply = choice(note_reply)
except KeyError:
note_reply = ""
parse_words = [
"first",
"last",
"fullname",
"id",
"username",
"mention",
"chatname",
]
text = await escape_mentions_using_curly_brackets(m, note_reply, parse_words)
teks, button = await parse_button(text)
button = await build_keyboard(button)
button = ikb(button) if button else None
textt = teks
try:
if msgtype == Types.TEXT:
if button:
try:
await reply_text(
textt,
# parse_mode=enums.ParseMode.MARKDOWN,
reply_markup=button,
disable_web_page_preview=True,
quote=True,
)
return
except RPCError as ef:
await reply_text(
"An error has occured! Cannot parse note.",
quote=True,
)
LOGGER.error(ef)
LOGGER.error(format_exc())
return
else:
await reply_text(
textt,
# parse_mode=enums.ParseMode.MARKDOWN,
quote=True,
disable_web_page_preview=True,
)
return
elif msgtype in (
Types.STICKER,
Types.VIDEO_NOTE,
Types.CONTACT,
Types.ANIMATED_STICKER,
):
await (await send_cmd(c, msgtype))(
m.chat.id,
getnotes["fileid"],
reply_markup=button,
reply_to_message_id=reply_msg_id,
)
elif button:
try:
await (await send_cmd(c, msgtype))(
m.chat.id,
getnotes["fileid"],
caption=textt,
# parse_mode=enums.ParseMode.MARKDOWN,
reply_markup=button,
reply_to_message_id=reply_msg_id,
)
return
except RPCError as ef:
await m.reply_text(
textt,
# parse_mode=enums.ParseMode.MARKDOWN,
reply_markup=button,
disable_web_page_preview=True,
reply_to_message_id=reply_msg_id,
)
LOGGER.error(ef)
LOGGER.error(format_exc())
return
else:
await (await send_cmd(c, msgtype))(
m.chat.id,
getnotes["fileid"],
caption=textt,
# parse_mode=enums.ParseMode.MARKDOWN,
reply_markup=button,
reply_to_message_id=reply_msg_id,
)
except Exception as e:
await m.reply_text(f"Error in notes: {e}")
return
async def get_raw_note(c: Gojo, m: Message, note: str):
"""Get the note in raw format, so it can updated by just copy and pasting."""
all_notes = {i[0] for i in db.get_all_notes(m.chat.id)}
if m and not m.from_user:
return
if note not in all_notes:
await m.reply_text("This note does not exists!")
return
getnotes = db.get_note(m.chat.id, note)
msg_id = m.reply_to_message.id if m.reply_to_message else m.id
msgtype = getnotes["msgtype"]
if not getnotes:
await m.reply_text("Error: Cannot find a type for this note!!")
return
if msgtype == Types.TEXT:
teks = getnotes["note_value"]
await m.reply_text(
teks, parse_mode=enums.ParseMode.DISABLED, reply_to_message_id=msg_id
)
elif msgtype in (
Types.STICKER,
Types.VIDEO_NOTE,
Types.CONTACT,
Types.ANIMATED_STICKER,
):
await (await send_cmd(c, msgtype))(
m.chat.id,
getnotes["fileid"],
reply_to_message_id=msg_id,
)
else:
teks = getnotes["note_value"] or ""
await (await send_cmd(c, msgtype))(
m.chat.id,
getnotes["fileid"],
caption=teks,
parse_mode=enums.ParseMode.DISABLED,
reply_to_message_id=msg_id,
)
return
@Gojo.on_message(filters.regex(r"^#[^\s]+") & filters.group & ~filters.bot)
async def hash_get(c: Gojo, m: Message):
# If not from user, then return
try:
note = (m.text[1:]).lower()
except TypeError:
return
all_notes = {i[0] for i in db.get_all_notes(m.chat.id)}
if note not in all_notes:
# don't reply to all messages starting with #
return
priv_notes_status = db_settings.get_privatenotes(m.chat.id)
await get_note_func(c, m, note, priv_notes_status)
return
@Gojo.on_message(command("get") & filters.group & ~filters.bot)
async def get_note(c: Gojo, m: Message):
if len(m.text.split()) == 2:
priv_notes_status = db_settings.get_privatenotes(m.chat.id)
note = ((m.text.split())[1]).lower()
all_notes = {i[0] for i in db.get_all_notes(m.chat.id)}
if note not in all_notes:
await m.reply_text("This note does not exists!")
return
await get_note_func(c, m, note, priv_notes_status)
elif len(m.text.split()) == 3 and (m.text.split())[2] in ["noformat", "raw"]:
note = ((m.text.split())[1]).lower()
await get_raw_note(c, m, note)
else:
await m.reply_text("Give me a note tag!")
return
return
@Gojo.on_message(command(["privnotes", "privatenotes"]) & admin_filter & ~filters.bot)
async def priv_notes(_, m: Message):
chat_id = m.chat.id
if len(m.text.split()) == 2:
option = (m.text.split())[1]
if option in ("on", "yes"):
db_settings.set_privatenotes(chat_id, True)
msg = "Set private notes to On"
elif option in ("off", "no"):
db_settings.set_privatenotes(chat_id, False)
msg = "Set private notes to Off"
else:
msg = "Enter correct option"
await m.reply_text(msg)
elif len(m.text.split()) == 1:
curr_pref = db_settings.get_privatenotes(m.chat.id)
msg = msg = f"Private Notes: {curr_pref}"
await m.reply_text(msg)
else:
await m.replt_text("Check help on how to use this command!")
return
@Gojo.on_message(command("notes") & filters.group & ~filters.bot)
async def local_notes(c: Gojo, m: Message):
getnotes = db.get_all_notes(m.chat.id)
if not getnotes:
await m.reply_text(f"There are no notes in {m.chat.title}.")
return
msg_id = m.reply_to_message.id if m.reply_to_message else m.id
if curr_pref := db_settings.get_privatenotes(m.chat.id):
pm_kb = ikb(
[
[
(
"All Notes",
f"https://t.me/{c.me.username}?start=notes_{m.chat.id}",
"url",
),
],
],
)
await m.reply_text(
"Click on the button below to get notes!",
quote=True,
reply_markup=pm_kb,
)
return
rply = f"Notes in {m.chat.title}:\n"
for x in getnotes:
rply += f"-> #{x[0]}
\n"
rply += "\nYou can get a note by #notename or /get notename
"
await m.reply_text(rply, reply_to_message_id=msg_id)
return
@Gojo.on_message(command("clear") & admin_filter & ~filters.bot)
async def clear_note(_, m: Message):
if len(m.text.split()) <= 1:
await m.reply_text("What do you want to clear?")
return
note = m.text.split()[1].lower()
getnote = db.rm_note(m.chat.id, note)
if not getnote:
await m.reply_text("This note does not exist!")
return
await m.reply_text(f"Note '`{note}`' deleted!")
return
@Gojo.on_message(command("clearall") & owner_filter & ~filters.bot)
async def clear_allnote(_, m: Message):
all_notes = {i[0] for i in db.get_all_notes(m.chat.id)}
if not all_notes:
await m.reply_text("No notes are there in this chat")
return
await m.reply_text(
"Are you sure you want to clear all notes?",
reply_markup=ikb(
[[("⚠️ Confirm", "clear_notes"), ("❌ Cancel", "close_admin")]],
),
)
return
@Gojo.on_callback_query(filters.regex("^clear_notes$"))
async def clearallnotes_callback(_, q: CallbackQuery):
user_id = q.from_user.id
user_status = (await q.message.chat.get_member(user_id)).status
if user_status not in {CMS.OWNER, CMS.ADMINISTRATOR}:
await q.answer(
"You're not even an admin, don't try this explosive shit!",
show_alert=True,
)
return
if user_status != CMS.OWNER:
await q.answer(
"You're just an admin, not owner\nStay in your limits!",
show_alert=True,
)
return
db.rm_all_notes(q.message.chat.id)
await q.message.edit_text("Cleared all notes!")
return
__PLUGIN__ = "notes"
_DISABLE_CMDS_ = ["notes"]
__alt_name__ = ["groupnotes", "snips", "notes"]
__HELP__ = """
**Notes**
Save a note, get that, even you can delete that note.
This note only avaiable for your whole group!
Only admins can save and deletenotes, anyone can get them.
• /save `` <`note content or reply to message>`
Save a note, you can get or delete that later.
• /get `` or #
Get that note, if avaiable.
• /get `` noformat or /get `` raw
Get that note in raw format, so you can edit and update it.
• /clear ``
Delete that note, if avaiable.
• /clearall
Clears all notes in the chat!
**NOTE:** Can only be used by owner of chat!
• /saved or /notes
Get all your notes, if too much notes, please use this in your saved message instead!
• /privatenotes ``: Whether to turn private rules on or off, prevents spam in chat when people use notes command.
**Note Format**
Check /markdownhelp for help related to formatting!"""