File size: 13,911 Bytes
ca4eb6d
007891e
11ae35a
c0ed2cf
11ae35a
c0ed2cf
6dcea66
11ae35a
 
 
 
87abec5
11ae35a
 
87abec5
11ae35a
 
 
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c973f55
ca4eb6d
 
 
 
87abec5
ca4eb6d
 
 
 
 
 
 
c62ca93
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aef1161
ca4eb6d
 
 
 
 
 
 
 
5ec9c41
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5ec9c41
ca4eb6d
 
 
 
 
6cef7ec
 
 
 
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
5ec9c41
ca4eb6d
 
 
 
 
 
 
5ec9c41
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
5ec9c41
ca4eb6d
 
 
6cef7ec
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c15d499
ca4eb6d
 
 
 
 
 
 
 
2aca525
 
 
ca4eb6d
6cef7ec
 
 
 
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
5ec9c41
ca4eb6d
 
6cef7ec
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c62ca93
ca4eb6d
 
 
 
 
 
c15d499
ca4eb6d
89ad488
ca4eb6d
 
 
 
 
c62ca93
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5bc27d3
ca4eb6d
 
 
 
 
5bc27d3
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9da6fea
709df35
096ee5f
709df35
 
9da6fea
 
 
d5348c6
9da6fea
 
d5348c6
9da6fea
 
d5348c6
9da6fea
 
d5348c6
9da6fea
 
d5348c6
9da6fea
 
 
d5348c6
9da6fea
 
d5348c6
9da6fea
d5348c6
af1662b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
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"<code>{m.text}</code>\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"<code>{m.text}</code>\n\nError: There is no text in here!")
        return

    if not data_type:
        await m.reply_text(
            f"<code>{m.text}</code>\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 <code>{note_name}</code>!\nGet it with <code>/get {note_name}</code> or <code>#{note_name}</code>",
    )
    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 <code>{note_name}</code>",
            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("<b>Error:</b> 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("<b>Error:</b> 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 <b>{m.chat.title}</b>.")
        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 <b>{m.chat.title}</b>:\n"
    for x in getnotes:
        rply += f"-> <code>#{x[0]}</code>\n"
    rply += "\nYou can get a note by #notename or <code>/get notename</code>"

    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 `<notename>` <`note content or reply to message>`
    Save a note, you can get or delete that later.

• /get `<note>` or #<note>
    Get that note, if avaiable.

• /get `<note>` noformat or /get `<note>` raw
    Get that note in raw format, so you can edit and update it.

• /clear `<note>`
    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 `<on/yes/no/off>`: 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!"""