public inbox for [email protected]
 help / color / mirror / Atom feed
* [PATCH v1 00/26] The complete version of the Discord bot
@ 2022-10-01 13:03 Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 01/26] discord: Add get_atom_urls() to get the list of atom URLs Muhammad Rizki
                   ` (26 more replies)
  0 siblings, 27 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Hi, sir
In this series, I create the complete version of the Discord bot.
This series contains slash commands, events, and basic commands for
syncing the slash commands to the global. Add getter and deletion
database methods. Add a mail listener to get the new lore email message.
Add filters to only the lore admin who can use the atom and
broadcast manager slash commands.

This series contains fix a bug in the storage management on the
atom/utils.py, because I forgot to test the Telegram bot in the past.

Rename some utility functions to make it simple and readable. Add a
button UI to go direct to its lore email message. Some changes on the
on_ready event give a tip message on what to do when the bot first
starts.

There are 26 patches in this series:
- Patch 1 is to add get_atom_urls() to get the list of atom URLs in the DB
- Patch 2 is to fix the storage management on the atom/utils.py
- Patch 3 is to add get_broadcast_chats() to get the list of Discord ch
- Patch 4 is to add get_email_id() to get the email ID of the PK emails
- Patch 5 is to add get_reply_id() to get the Discord message ID
- Patch 6 is to inherit Getter() to the DBMethods() class
- Patch 7 is to add delet_atom() to delete specific atom URL
- Patch 8 is to add delete_broadcast() to delete current Discord channel
- Patch 9 is to inherit Deletion() to the DBMethods() class
- Patch 10 is to inherit DBMethods() to the DB() class
- Patch 11 is to implement the created DB() class in the GWClient() class
- Patch 12 is to rename some utility functions
- Patch 13 is to add a FullMessageBtn() button URL class to go to the lore
- Patch 14 is to add a @filters.wait_on_limit() to handle the rate limit
- Patch 15 is to add send lore email message functions
- Patch 16 is to add a mail listener to get the new lore email message
- Patch 17 is to implement the mail Listener() class in the dc.py
- Patch 18 is to add a @filters.lore_admin() to filter only the lore admin
- Patch 19 is to add a `/atom list` slash command
- Patch 20 is to add a `/atom add` slash command
- Patch 21 is to add a `/atom delete` slash command
- Patch 22 is to add a channel_link() util function in the atom/utils.py
- Patch 23 is to add a `/broadcast list` slash command
- Patch 24 is to add a `/broadcast add` slash command
- Patch 25 is to add a `/broadcast delete` slash command
- Patch 26 is to add a tip message on the on_ready event

How to use:
1. Execute the db.sql file in the daemon directory,
2. Setup .env file, the example is there with suffix .example, this
   file name must remove the suffix name .example,
3. Set up the config.py in each bot directory, such as dscord and
   telegram. The example is there with suffix .example & the file name
   must remove suffix name .example,
4. Run `pip3 install -r requirements.txt` in each bot directory,
5. STORAGE_DIR env value must `storage` to make it work fine,
6. Run the bot by `python3 dc.py` or `python3 tg.py`.

Both tested and worked fine. Please give it a test if I still forgot
something like in the past, thanks!

Muhammad Rizki (26):
  discord: Add get_atom_urls() to get the list of atom URLs
  Fix the storage management after the refactor was happened
  discord: Add get_broadcast_chats() to get the list of broadcast chats
  discord: Add get_email_id() in getter directory
  discord: Add get_reply_id() in getter directory
  discord: Inherit Getter() class to the DBMethods() class
  discord: Add delete_atom() in deletion directory
  discord: Add delete_broadcast() in deletion directory
  discord: Inherit the Deletion() class to the DBMethods() class
  discord: Inherit the DBMethods() class to the DB() class
  discord: Use the created DB() class
  telegram: Rename some utility functions
  discord: Add a FullMessageBtn() class in models
  discord: Add filters.wait_on_limit() decorator
  discord: Add send lore email message functions
  discord: Add mail listener
  discord: Implement the mail Listener() class
  discord: Add @filters.lore_admin() decorator
  discord: Add a list of atom URL slash command
  discord: Add an add atom slash command
  discord: Add a delete atom slash command
  discord: Add channel_link() in the atom/utils.py
  discord: Add a list broadcast slash command
  discord: Add an add broadcast slash command
  discord: Add a delete broadcast slash command
  discord: Change the on_ready message

 daemon/atom/utils.py                          |  81 ++++++---
 daemon/dc.py                                  |  30 +++-
 daemon/dscord/database/core.py                |   5 +-
 daemon/dscord/database/methods/__init__.py    |   6 +-
 .../database/methods/deletion/__init__.py     |  14 ++
 .../database/methods/deletion/delete_atom.py  |  15 ++
 .../methods/deletion/delete_broadcast.py      |  15 ++
 .../database/methods/getter/__init__.py       |  18 ++
 .../database/methods/getter/get_atom_urls.py  |  21 +++
 .../methods/getter/get_broadcast_chats.py     |  21 +++
 .../database/methods/getter/get_email_id.py   |  60 +++++++
 .../database/methods/getter/get_reply.py      |  33 ++++
 daemon/dscord/gnuweeb/client.py               |  52 +++++-
 daemon/dscord/gnuweeb/filters.py              |  53 ++++++
 daemon/dscord/gnuweeb/models/__init__.py      |   6 +
 .../dscord/gnuweeb/models/full_message_btn.py |  12 ++
 daemon/dscord/gnuweeb/plugins/__init__.py     |   4 +-
 .../dscord/gnuweeb/plugins/events/on_ready.py |   7 +-
 .../plugins/slash_commands/__init__.py        |  13 ++
 .../plugins/slash_commands/manage_atom.py     |  81 +++++++++
 .../slash_commands/manage_broadcast.py        |  84 ++++++++++
 daemon/dscord/mailer/__init__.py              |   7 +
 daemon/dscord/mailer/listener.py              | 154 ++++++++++++++++++
 daemon/telegram/mailer/listener.py            |   2 +-
 daemon/telegram/packages/client.py            |   6 +-
 25 files changed, 770 insertions(+), 30 deletions(-)
 create mode 100644 daemon/dscord/database/methods/deletion/__init__.py
 create mode 100644 daemon/dscord/database/methods/deletion/delete_atom.py
 create mode 100644 daemon/dscord/database/methods/deletion/delete_broadcast.py
 create mode 100644 daemon/dscord/database/methods/getter/__init__.py
 create mode 100644 daemon/dscord/database/methods/getter/get_atom_urls.py
 create mode 100644 daemon/dscord/database/methods/getter/get_broadcast_chats.py
 create mode 100644 daemon/dscord/database/methods/getter/get_email_id.py
 create mode 100644 daemon/dscord/database/methods/getter/get_reply.py
 create mode 100644 daemon/dscord/gnuweeb/filters.py
 create mode 100644 daemon/dscord/gnuweeb/models/__init__.py
 create mode 100644 daemon/dscord/gnuweeb/models/full_message_btn.py
 create mode 100644 daemon/dscord/gnuweeb/plugins/slash_commands/__init__.py
 create mode 100644 daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py
 create mode 100644 daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py
 create mode 100644 daemon/dscord/mailer/__init__.py
 create mode 100644 daemon/dscord/mailer/listener.py


base-commit: fdbccda0372a7869b7ac6b8c5b31ec1761b5e084
--
Muhammad Rizki

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v1 01/26] discord: Add get_atom_urls() to get the list of atom URLs
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 02/26] Fix the storage management after the refactor was happened Muhammad Rizki
                   ` (25 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add get_atom_urls() in the database getter directory to get the list of
atom URLs. With this, we can display and manage them.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../database/methods/getter/__init__.py       | 12 +++++++++++
 .../database/methods/getter/get_atom_urls.py  | 21 +++++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 daemon/dscord/database/methods/getter/__init__.py
 create mode 100644 daemon/dscord/database/methods/getter/get_atom_urls.py

diff --git a/daemon/dscord/database/methods/getter/__init__.py b/daemon/dscord/database/methods/getter/__init__.py
new file mode 100644
index 0000000..3670448
--- /dev/null
+++ b/daemon/dscord/database/methods/getter/__init__.py
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+
+from .get_atom_urls import GetAtomURL
+
+
+class Getter(
+	GetAtomURL
+): pass
diff --git a/daemon/dscord/database/methods/getter/get_atom_urls.py b/daemon/dscord/database/methods/getter/get_atom_urls.py
new file mode 100644
index 0000000..19fe49e
--- /dev/null
+++ b/daemon/dscord/database/methods/getter/get_atom_urls.py
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+
+class GetAtomURL:
+
+	def get_atom_urls(self):
+		'''
+		Get lore kernel raw email URLs.
+		- Return list of raw email URLs: `List[str]`
+		'''
+		q = """
+			SELECT dc_atoms.url
+			FROM dc_atoms
+		"""
+		self.cur.execute(q)
+		urls = self.cur.fetchall()
+
+		return [u[0] for u in urls]
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 02/26] Fix the storage management after the refactor was happened
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 01/26] discord: Add get_atom_urls() to get the list of atom URLs Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 03/26] discord: Add get_broadcast_chats() to get the list of broadcast chats Muhammad Rizki
                   ` (24 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

I didn't test the Telegram bot when the refactor happened. I forgot to
update the utility function, like creating a file or patch directory
into the `storage` directory, which is so important.

Add the `platform` parameter to the necessary functions and add
quote_reply() for the Discord bot to create a vertical line reply
display. The `platform` parameter is to tell it for `telegram` or
`discord`. This will place the patch into its own `storage` directory.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/atom/utils.py               | 75 ++++++++++++++++++++++--------
 daemon/telegram/mailer/listener.py |  2 +-
 daemon/telegram/packages/client.py |  4 +-
 3 files changed, 59 insertions(+), 22 deletions(-)

diff --git a/daemon/atom/utils.py b/daemon/atom/utils.py
index c428a33..f813f39 100644
--- a/daemon/atom/utils.py
+++ b/daemon/atom/utils.py
@@ -113,25 +113,39 @@ def consruct_to_n_cc(to: list, cc: list):
 	return ret
 
 
-def gen_temp(name: str):
+def gen_temp(name: str, platform: str):
+	platform = platform.lower()
+	plt_ls = ["telegram", "discord"]
+
+	if platform not in plt_ls:
+		t = f"Platform {platform} is not found, "
+		t += f"only {', '.join(plt_ls)} is available"
+		raise ValueError(f"Platform {platform} is not found")
+
 	md5 = hashlib.md5(name.encode()).hexdigest()
-	ret = os.getenv("STORAGE_DIR", "storage") + "/" + md5
+	store_dir = os.getenv("STORAGE_DIR", "storage")
+	platform = platform.replace("discord", "dscord")
+	path = f"{platform}/{store_dir}/{md5}"
 	try:
-		os.mkdir(ret)
+		os.mkdir(path)
 	except FileExistsError:
 		pass
 
-	return ret
+	return path
 
 
-def extract_body(thread: Message):
+def extract_body(thread: Message, platform: str):
 	if not thread.is_multipart():
-		p = thread.get_payload(decode=True)
-		return f"{p.decode(errors='replace')}\n".lstrip(), []
+		p = thread.get_payload(decode=True).decode(errors='replace')
+
+		if platform == "discord":
+			p = quote_reply(p)
+
+		return f"{p}\n".lstrip(), []
 
 	ret = ""
 	files = []
-	temp = gen_temp(str(uuid.uuid4()))
+	temp = gen_temp(str(uuid.uuid4()), platform)
 	for p in thread.get_payload():
 		fname = p.get_filename()
 		payload = p.get_payload(decode=True)
@@ -164,35 +178,42 @@ def __is_patch(subject, content):
 	return True
 
 
-def create_template(thread: Message, to=None, cc=None):
+def create_template(thread: Message, platform: str, to=None, cc=None):
 	if not to:
 		to = extract_list("to", thread)
 	if not cc:
 		cc = extract_list("cc", thread)
+	if platform == "telegram":
+		substr = 4000
+		border = f"\n<code>{'-'*72}</code>"
+	else:
+		substr = 1900
+		border = f"\n{'-'*80}"
 
 	subject = thread.get('subject')
 	ret = f"From: {thread.get('from')}\n"
 	ret += consruct_to_n_cc(to, cc)
 	ret += f"Date: {thread.get('date')}\n"
 	ret += f"Subject: {subject}\n\n"
-	content, files = extract_body(thread)
+	content, files = extract_body(thread, platform)
 	is_patch = __is_patch(subject, content)
 
 	if is_patch:
 		ret += content
 	else:
 		ret += content.strip().replace("\t", "        ")
-		if len(ret) >= 4000:
-			ret = ret[:4000] + "..."
 
-		ret = fix_utf8_char(ret)
-		ret += f"\n<code>{'-'*72}</code>"
+		if len(ret) >= substr:
+			ret = ret[:substr] + "..."
+
+		ret = fix_utf8_char(ret, platform == "telegram")
+		ret += border
 
 	return ret, files, is_patch
 
 
-def prepare_send_patch(mail, text, url):
-	tmp = gen_temp(url)
+def prepare_send_patch(mail, text, url, platform: str):
+	tmp = gen_temp(url, platform)
 	fnm = str(mail.get("subject"))
 	sch = re.search(PATCH_PATTERN, fnm, re.IGNORECASE)
 
@@ -210,7 +231,10 @@ def prepare_send_patch(mail, text, url):
 	with open(file, "wb") as f:
 		f.write(bytes(text, encoding="utf8"))
 
-	caption = "#patch #ml\n" + fix_utf8_char(cap)
+	caption = "#patch #ml"
+	if platform == "telegram":
+		caption += fix_utf8_char("\n" + cap, True)
+
 	return tmp, file, caption, url
 
 
@@ -218,9 +242,11 @@ def clean_up_after_send_patch(tmp):
 	shutil.rmtree(tmp)
 
 
-def fix_utf8_char(text: str):
-	text = text.rstrip().replace("�"," ")
-	return html.escape(html.escape(text))
+def fix_utf8_char(text: str, html_escape: bool = True):
+	t = text.rstrip().replace("�"," ")
+	if html_escape:
+		t = html.escape(html.escape(text))
+	return t
 
 
 EMAIL_MSG_ID_PATTERN = r"<([^\<\>]+)>"
@@ -240,6 +266,15 @@ async def is_atom_url(text: str):
 			return mime == "application/atom+xml"
 	except: return False
 
+def quote_reply(text: str):
+	a = ""
+	for b in text.split("\n"):
+		b = b.replace(">\n", "> ")
+		if b.startswith(">"):
+			a += "> "
+		a += f"{b}\n"
+	return a
+
 def remove_command(text: str):
 	txt = text.split(" ")
 	txt = text.replace(txt[0] + " ","")
diff --git a/daemon/telegram/mailer/listener.py b/daemon/telegram/mailer/listener.py
index decf85f..208aed0 100644
--- a/daemon/telegram/mailer/listener.py
+++ b/daemon/telegram/mailer/listener.py
@@ -99,7 +99,7 @@ class Bot():
 			#
 			return False
 
-		text, files, is_patch = utils.create_template(mail)
+		text, files, is_patch = utils.create_template(mail, "telegram")
 		reply_to = self.get_reply(mail, tg_chat_id)
 		url = str(re.sub(r"/raw$", "", url))
 
diff --git a/daemon/telegram/packages/client.py b/daemon/telegram/packages/client.py
index 4f9c596..17061ec 100644
--- a/daemon/telegram/packages/client.py
+++ b/daemon/telegram/packages/client.py
@@ -56,7 +56,9 @@ class DaemonClient(Client):
 		parse_mode: ParseMode = ParseMode.HTML
 	) -> Message:
 		print("[send_patch_email]")
-		tmp, doc, caption, url = utils.prepare_send_patch(mail, text, url)
+		tmp, doc, caption, url = utils.prepare_send_patch(
+			mail, text, url, "telegram"
+		)
 		m = await self.send_document(
 			chat_id=chat_id,
 			document=doc,
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 03/26] discord: Add get_broadcast_chats() to get the list of broadcast chats
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 01/26] discord: Add get_atom_urls() to get the list of atom URLs Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 02/26] Fix the storage management after the refactor was happened Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 04/26] discord: Add get_email_id() in getter directory Muhammad Rizki
                   ` (23 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add get_broadcast_chats() to get the list of broadcast chats. Useful for
display and manage them.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../database/methods/getter/__init__.py       |  4 +++-
 .../methods/getter/get_broadcast_chats.py     | 21 +++++++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100644 daemon/dscord/database/methods/getter/get_broadcast_chats.py

diff --git a/daemon/dscord/database/methods/getter/__init__.py b/daemon/dscord/database/methods/getter/__init__.py
index 3670448..2f4bec7 100644
--- a/daemon/dscord/database/methods/getter/__init__.py
+++ b/daemon/dscord/database/methods/getter/__init__.py
@@ -5,8 +5,10 @@
 
 
 from .get_atom_urls import GetAtomURL
+from .get_broadcast_chats import GetBroadcastChats
 
 
 class Getter(
-	GetAtomURL
+	GetAtomURL,
+	GetBroadcastChats
 ): pass
diff --git a/daemon/dscord/database/methods/getter/get_broadcast_chats.py b/daemon/dscord/database/methods/getter/get_broadcast_chats.py
new file mode 100644
index 0000000..979912b
--- /dev/null
+++ b/daemon/dscord/database/methods/getter/get_broadcast_chats.py
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+
+class GetBroadcastChats:
+
+	def get_broadcast_chats(self):
+		'''
+		Get broadcast chats that are currently
+		listening for new email.
+		- Return list of chat object: `List[Object]`
+		'''
+		q = """
+			SELECT *
+			FROM dc_broadcasts
+		"""
+		self.cur.execute(q)
+
+		return self.cur.fetchall()
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 04/26] discord: Add get_email_id() in getter directory
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (2 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 03/26] discord: Add get_broadcast_chats() to get the list of broadcast chats Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 05/26] discord: Add get_reply_id() " Muhammad Rizki
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add get_email_id() to get the email id of the primary key `dc_emails`
database table. This function is to return an email id to insert it into
the save_discord_mail() parameter because the `dc_emails` and the
`dc_mail_msg` database table are relationships.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../database/methods/getter/__init__.py       |  4 +-
 .../database/methods/getter/get_email_id.py   | 60 +++++++++++++++++++
 2 files changed, 63 insertions(+), 1 deletion(-)
 create mode 100644 daemon/dscord/database/methods/getter/get_email_id.py

diff --git a/daemon/dscord/database/methods/getter/__init__.py b/daemon/dscord/database/methods/getter/__init__.py
index 2f4bec7..0f4b976 100644
--- a/daemon/dscord/database/methods/getter/__init__.py
+++ b/daemon/dscord/database/methods/getter/__init__.py
@@ -6,9 +6,11 @@
 
 from .get_atom_urls import GetAtomURL
 from .get_broadcast_chats import GetBroadcastChats
+from .get_email_id import GetEmailID
 
 
 class Getter(
 	GetAtomURL,
-	GetBroadcastChats
+	GetBroadcastChats,
+	GetEmailID
 ): pass
diff --git a/daemon/dscord/database/methods/getter/get_email_id.py b/daemon/dscord/database/methods/getter/get_email_id.py
new file mode 100644
index 0000000..8c27340
--- /dev/null
+++ b/daemon/dscord/database/methods/getter/get_email_id.py
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+# Copyright (C) 2022  Ammar Faizi <[email protected]>
+#
+
+
+class GetEmailID:
+
+	def get_email_id(self, email_id, chat_id):
+		'''
+		Determine whether the email needs to be sent to @tg_chat_id.
+		 - Return an email id (PK) if it needs to be sent
+		 - Return None if it doesn't need to be sent
+		'''
+		if self.__is_sent(email_id, chat_id):
+			return
+
+		res = self.__email_id(email_id)
+		if not bool(res):
+			return
+
+		return int(res[0])
+
+
+	def __is_sent(self, email_id, channel_id):
+		'''
+		Checking if this email has already been sent
+		or not.
+		 - Return True if it's already been sent
+		'''
+		q = """
+			SELECT dc_emails.id, dc_mail_msg.id FROM dc_emails
+			LEFT JOIN dc_mail_msg
+			ON dc_emails.id = dc_mail_msg.email_id
+			WHERE dc_emails.message_id = %(email_msg_id)s
+			AND dc_mail_msg.channel_id = %(channel_id)s
+			LIMIT 1
+		"""
+
+		self.cur.execute(q, {
+			"email_msg_id": email_id,
+			"channel_id": channel_id
+		})
+		res = self.cur.fetchone()
+		return bool(res)
+
+
+	def __email_id(self, email_id):
+		'''
+		Get the email id if match with the email message_id.
+		 - Return the result if it's match and exists
+		'''
+		q = """
+			SELECT id FROM dc_emails WHERE message_id = %(email_id)s
+		"""
+
+		self.cur.execute(q, {"email_id": email_id})
+		res = self.cur.fetchone()
+		return res
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 05/26] discord: Add get_reply_id() in getter directory
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (3 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 04/26] discord: Add get_email_id() in getter directory Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 06/26] discord: Inherit Getter() class to the DBMethods() class Muhammad Rizki
                   ` (21 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add get_reply_id() to get the Discord message ID of the lore email
message sent to the Discord channel. With this, the bot can reply to the
sent message of the lore email.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../database/methods/getter/__init__.py       |  4 ++-
 .../database/methods/getter/get_reply.py      | 33 +++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 daemon/dscord/database/methods/getter/get_reply.py

diff --git a/daemon/dscord/database/methods/getter/__init__.py b/daemon/dscord/database/methods/getter/__init__.py
index 0f4b976..63cab01 100644
--- a/daemon/dscord/database/methods/getter/__init__.py
+++ b/daemon/dscord/database/methods/getter/__init__.py
@@ -7,10 +7,12 @@
 from .get_atom_urls import GetAtomURL
 from .get_broadcast_chats import GetBroadcastChats
 from .get_email_id import GetEmailID
+from .get_reply import GetDiscordReply
 
 
 class Getter(
 	GetAtomURL,
 	GetBroadcastChats,
-	GetEmailID
+	GetEmailID,
+	GetDiscordReply
 ): pass
diff --git a/daemon/dscord/database/methods/getter/get_reply.py b/daemon/dscord/database/methods/getter/get_reply.py
new file mode 100644
index 0000000..870dc84
--- /dev/null
+++ b/daemon/dscord/database/methods/getter/get_reply.py
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+# Copyright (C) 2022  Ammar Faizi <[email protected]>
+#
+
+
+class GetDiscordReply:
+
+	def get_reply_id(self, email_id, channel_id):
+		'''
+		Get Telegram message ID sent match with
+		email message ID and Telegram chat ID.
+		- Return Telegram message ID if exists: `int`
+		- Return None if not exists`
+		'''
+		q = """
+			SELECT dc_mail_msg.dc_msg_id
+			FROM dc_emails INNER JOIN dc_mail_msg
+			ON dc_emails.id = dc_mail_msg.email_id
+			WHERE dc_emails.message_id = %(email_msg_id)s
+			AND dc_mail_msg.channel_id = %(channel_id)s
+		"""
+
+		self.cur.execute(q, {
+			"email_msg_id": email_id,
+			"channel_id": channel_id
+		})
+		res = self.cur.fetchone()
+		if not bool(res):
+			return None
+
+		return res[0]
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 06/26] discord: Inherit Getter() class to the DBMethods() class
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (4 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 05/26] discord: Add get_reply_id() " Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 07/26] discord: Add delete_atom() in deletion directory Muhammad Rizki
                   ` (20 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Use Getter() class to inherit it to the DBMethods() class, so all the
get functions in the getter directory will be in a relationship with the
DBMethods() class.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/database/methods/__init__.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/daemon/dscord/database/methods/__init__.py b/daemon/dscord/database/methods/__init__.py
index 189ec67..625a632 100644
--- a/daemon/dscord/database/methods/__init__.py
+++ b/daemon/dscord/database/methods/__init__.py
@@ -5,8 +5,10 @@
 
 
 from .insertion import Insertion
+from .getter import Getter
 
 
 class DBMethods(
-	Insertion
+	Insertion,
+	Getter
 ): pass
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 07/26] discord: Add delete_atom() in deletion directory
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (5 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 06/26] discord: Inherit Getter() class to the DBMethods() class Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 08/26] discord: Add delete_broadcast() " Muhammad Rizki
                   ` (19 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add delete_atom() for delete the specific atom URL.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../dscord/database/methods/deletion/__init__.py  | 12 ++++++++++++
 .../database/methods/deletion/delete_atom.py      | 15 +++++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 daemon/dscord/database/methods/deletion/__init__.py
 create mode 100644 daemon/dscord/database/methods/deletion/delete_atom.py

diff --git a/daemon/dscord/database/methods/deletion/__init__.py b/daemon/dscord/database/methods/deletion/__init__.py
new file mode 100644
index 0000000..988bbee
--- /dev/null
+++ b/daemon/dscord/database/methods/deletion/__init__.py
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+
+from .delete_atom import DeleteAtom
+
+
+class Deletion(
+	DeleteAtom,
+): pass
diff --git a/daemon/dscord/database/methods/deletion/delete_atom.py b/daemon/dscord/database/methods/deletion/delete_atom.py
new file mode 100644
index 0000000..f2cbc2e
--- /dev/null
+++ b/daemon/dscord/database/methods/deletion/delete_atom.py
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+
+class DeleteAtom:
+
+	def delete_atom(self, atom: str):
+		q = """
+			DELETE FROM dc_atoms
+			WHERE url = %(atom)s
+		"""
+		self.cur.execute(q, {"atom": atom})
+		return self.cur.rowcount > 0
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 08/26] discord: Add delete_broadcast() in deletion directory
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (6 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 07/26] discord: Add delete_atom() in deletion directory Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 09/26] discord: Inherit the Deletion() class to the DBMethods() class Muhammad Rizki
                   ` (18 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add delete_broadcast() for delete the specific Discord channel
broadcast.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../dscord/database/methods/deletion/__init__.py  |  2 ++
 .../database/methods/deletion/delete_broadcast.py | 15 +++++++++++++++
 2 files changed, 17 insertions(+)
 create mode 100644 daemon/dscord/database/methods/deletion/delete_broadcast.py

diff --git a/daemon/dscord/database/methods/deletion/__init__.py b/daemon/dscord/database/methods/deletion/__init__.py
index 988bbee..e8a4466 100644
--- a/daemon/dscord/database/methods/deletion/__init__.py
+++ b/daemon/dscord/database/methods/deletion/__init__.py
@@ -5,8 +5,10 @@
 
 
 from .delete_atom import DeleteAtom
+from .delete_broadcast import DeleteBroadcast
 
 
 class Deletion(
 	DeleteAtom,
+	DeleteBroadcast
 ): pass
diff --git a/daemon/dscord/database/methods/deletion/delete_broadcast.py b/daemon/dscord/database/methods/deletion/delete_broadcast.py
new file mode 100644
index 0000000..6c8ef83
--- /dev/null
+++ b/daemon/dscord/database/methods/deletion/delete_broadcast.py
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+
+class DeleteBroadcast:
+
+	def delete_broadcast(self, channel_id: int):
+		q = """
+			DELETE FROM dc_broadcasts
+			WHERE channel_id = %(channel_id)s
+		"""
+		self.cur.execute(q, {"channel_id": channel_id})
+		return self.cur.rowcount > 0
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 09/26] discord: Inherit the Deletion() class to the DBMethods() class
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (7 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 08/26] discord: Add delete_broadcast() " Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 10/26] discord: Inherit the DBMethods() class to the DB() class Muhammad Rizki
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Use the Deletion() class to inherit it to the DBMethods() class.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/database/methods/__init__.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/daemon/dscord/database/methods/__init__.py b/daemon/dscord/database/methods/__init__.py
index 625a632..dbf94b2 100644
--- a/daemon/dscord/database/methods/__init__.py
+++ b/daemon/dscord/database/methods/__init__.py
@@ -6,9 +6,11 @@
 
 from .insertion import Insertion
 from .getter import Getter
+from .deletion import Deletion
 
 
 class DBMethods(
 	Insertion,
-	Getter
+	Getter,
+	Deletion
 ): pass
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 10/26] discord: Inherit the DBMethods() class to the DB() class
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (8 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 09/26] discord: Inherit the Deletion() class to the DBMethods() class Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 11/26] discord: Use the created " Muhammad Rizki
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Use the DBMethods() class to the DB() class, so all the methods
functions like insertion, getter, and deletion are relationship with the
DB() class. It's cleaner and manageable-maintainable.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/database/core.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/daemon/dscord/database/core.py b/daemon/dscord/database/core.py
index 1a25388..c34d7a8 100644
--- a/daemon/dscord/database/core.py
+++ b/daemon/dscord/database/core.py
@@ -5,7 +5,10 @@
 #
 
 
-class DB:
+from .methods import DBMethods
+
+
+class DB(DBMethods):
 	def __init__(self, conn):
 		self.conn = conn
 		self.conn.autocommit = True
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 11/26] discord: Use the created DB() class
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (9 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 10/26] discord: Inherit the DBMethods() class to the DB() class Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 12/26] telegram: Rename some utility functions Muhammad Rizki
                   ` (15 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Use the DB() class into the __init__() function of the GWClient() class
and add the MySQL connection to the GWClient() class parameter.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dc.py                    | 10 +++++++++-
 daemon/dscord/gnuweeb/client.py |  5 ++++-
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/daemon/dc.py b/daemon/dc.py
index ff29abe..9b86df2 100644
--- a/daemon/dc.py
+++ b/daemon/dc.py
@@ -5,6 +5,7 @@
 
 import os
 from dotenv import load_dotenv
+from mysql import connector
 
 from dscord.gnuweeb import GWClient
 
@@ -12,7 +13,14 @@ from dscord.gnuweeb import GWClient
 def main():
 	load_dotenv("discord.env")
 
-	client = GWClient()
+	client = GWClient(
+		db_conn=connector.connect(
+			host=os.getenv("DB_HOST"),
+			user=os.getenv("DB_USER"),
+			password=os.getenv("DB_PASS"),
+			database=os.getenv("DB_NAME")
+		)
+	)
 	client.run(os.getenv("DISCORD_TOKEN"), log_handler=None)
 
 
diff --git a/daemon/dscord/gnuweeb/client.py b/daemon/dscord/gnuweeb/client.py
index fa07fb1..7893f88 100644
--- a/daemon/dscord/gnuweeb/client.py
+++ b/daemon/dscord/gnuweeb/client.py
@@ -8,9 +8,12 @@ from discord.ext import commands
 from discord import Intents
 from dscord.config import ACTIVITY_NAME
 
+from dscord.database import DB
+
 
 class GWClient(commands.Bot):
-	def __init__(self) -> None:
+	def __init__(self, db_conn) -> None:
+		self.db = DB(db_conn)
 		intents = Intents.default()
 		intents.message_content = True
 		super().__init__(
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 12/26] telegram: Rename some utility functions
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (10 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 11/26] discord: Use the created " Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 13/26] discord: Add a FullMessageBtn() class in models Muhammad Rizki
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Rename prepare_send_patch() to prepare_patch and
clean_up_after_send_patch() to remove_patch() to make them easier to
read and practice.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/atom/utils.py               | 4 ++--
 daemon/telegram/packages/client.py | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/daemon/atom/utils.py b/daemon/atom/utils.py
index f813f39..bf1f0da 100644
--- a/daemon/atom/utils.py
+++ b/daemon/atom/utils.py
@@ -212,7 +212,7 @@ def create_template(thread: Message, platform: str, to=None, cc=None):
 	return ret, files, is_patch
 
 
-def prepare_send_patch(mail, text, url, platform: str):
+def prepare_patch(mail, text, url, platform: str):
 	tmp = gen_temp(url, platform)
 	fnm = str(mail.get("subject"))
 	sch = re.search(PATCH_PATTERN, fnm, re.IGNORECASE)
@@ -238,7 +238,7 @@ def prepare_send_patch(mail, text, url, platform: str):
 	return tmp, file, caption, url
 
 
-def clean_up_after_send_patch(tmp):
+def remove_patch(tmp):
 	shutil.rmtree(tmp)
 
 
diff --git a/daemon/telegram/packages/client.py b/daemon/telegram/packages/client.py
index 17061ec..686e5ef 100644
--- a/daemon/telegram/packages/client.py
+++ b/daemon/telegram/packages/client.py
@@ -56,7 +56,7 @@ class DaemonClient(Client):
 		parse_mode: ParseMode = ParseMode.HTML
 	) -> Message:
 		print("[send_patch_email]")
-		tmp, doc, caption, url = utils.prepare_send_patch(
+		tmp, doc, caption, url = utils.prepare_patch(
 			mail, text, url, "telegram"
 		)
 		m = await self.send_document(
@@ -73,5 +73,5 @@ class DaemonClient(Client):
 			])
 		)
 
-		utils.clean_up_after_send_patch(tmp)
+		utils.remove_patch(tmp)
 		return m
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 13/26] discord: Add a FullMessageBtn() class in models
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (11 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 12/26] telegram: Rename some utility functions Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 14/26] discord: Add filters.wait_on_limit() decorator Muhammad Rizki
                   ` (13 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add a FullMessageBtn() class to be able to render a button of a lore
email message on its footer. This class is a clickable URL to direct to
its lore email message.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/gnuweeb/client.py                  |  4 ++++
 daemon/dscord/gnuweeb/models/__init__.py         |  6 ++++++
 daemon/dscord/gnuweeb/models/full_message_btn.py | 12 ++++++++++++
 3 files changed, 22 insertions(+)
 create mode 100644 daemon/dscord/gnuweeb/models/__init__.py
 create mode 100644 daemon/dscord/gnuweeb/models/full_message_btn.py

diff --git a/daemon/dscord/gnuweeb/client.py b/daemon/dscord/gnuweeb/client.py
index 7893f88..02a1ac5 100644
--- a/daemon/dscord/gnuweeb/client.py
+++ b/daemon/dscord/gnuweeb/client.py
@@ -7,7 +7,11 @@ import discord
 from discord.ext import commands
 from discord import Intents
 from dscord.config import ACTIVITY_NAME
+from typing import Union
 
+from . import filters
+from . import models
+from atom import utils
 from dscord.database import DB
 
 
diff --git a/daemon/dscord/gnuweeb/models/__init__.py b/daemon/dscord/gnuweeb/models/__init__.py
new file mode 100644
index 0000000..c1d2a56
--- /dev/null
+++ b/daemon/dscord/gnuweeb/models/__init__.py
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+from .full_message_btn import FullMessageBtn
diff --git a/daemon/dscord/gnuweeb/models/full_message_btn.py b/daemon/dscord/gnuweeb/models/full_message_btn.py
new file mode 100644
index 0000000..b8d81cf
--- /dev/null
+++ b/daemon/dscord/gnuweeb/models/full_message_btn.py
@@ -0,0 +1,12 @@
+from discord import ui
+from discord import ButtonStyle
+
+
+class FullMessageBtn(ui.View):
+	def __init__(self, url: str):
+		super().__init__()
+		self.add_item(ui.Button(
+			label='See the full message',
+			style=ButtonStyle.gray,
+			url=url
+		))
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 14/26] discord: Add filters.wait_on_limit() decorator
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (12 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 13/26] discord: Add a FullMessageBtn() class in models Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 15/26] discord: Add send lore email message functions Muhammad Rizki
                   ` (12 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add wait_on_limit() decorator in filters.py to prevent the rate limit
hit for sending a message.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/gnuweeb/filters.py | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 daemon/dscord/gnuweeb/filters.py

diff --git a/daemon/dscord/gnuweeb/filters.py b/daemon/dscord/gnuweeb/filters.py
new file mode 100644
index 0000000..19f9445
--- /dev/null
+++ b/daemon/dscord/gnuweeb/filters.py
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+import discord
+import asyncio
+from typing import Any
+from functools import wraps
+
+
+def wait_on_limit(func):
+	@wraps(func)
+	async def callback(*args: Any) -> Any:
+		while True:
+			try:
+				return await func(*args)
+			except discord.errors.RateLimited as e:
+				_flood_exceptions(e)
+				print("[wait_on_limit]: Woken up from flood wait...")
+	return callback
+
+
+async def _flood_exceptions(e: "discord.errors.RateLimited"):
+	wait = e.retry_after
+	print(f"[wait_on_limit]: Sleeping for {wait} seconds due to Telegram limit")
+	await asyncio.sleep(wait)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 15/26] discord: Add send lore email message functions
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (13 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 14/26] discord: Add filters.wait_on_limit() decorator Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 16/26] discord: Add mail listener Muhammad Rizki
                   ` (11 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add send_text_email() and send_patch_email() in the
dscord/gnuweeb/client.py to send the lore email message to the Discord
channel.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/gnuweeb/client.py | 42 +++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/daemon/dscord/gnuweeb/client.py b/daemon/dscord/gnuweeb/client.py
index 02a1ac5..2506ec3 100644
--- a/daemon/dscord/gnuweeb/client.py
+++ b/daemon/dscord/gnuweeb/client.py
@@ -33,3 +33,45 @@ class GWClient(commands.Bot):
 			name=".gnuweeb.plugins",
 			package="dscord"
 		)
+
+
+	@filters.wait_on_limit
+	async def send_text_email(self, guild_id: int, chat_id: int, text: str,
+				reply_to: Union[int, None] = None, url: str = None):
+		print("[send_text_email]")
+		channel = self.get_channel(chat_id)
+
+		return await channel.send(
+			content=text,
+			reference=discord.MessageReference(
+				guild_id=guild_id,
+				channel_id=chat_id,
+				message_id=reply_to
+			) if reply_to else None,
+			view=models.FullMessageBtn(url)
+		)
+
+
+	@filters.wait_on_limit
+	async def send_patch_email(self, mail, guild_id: int, chat_id: int, text: str,
+				reply_to: Union[int, None] = None, url: str = None):
+		print("[send_patch_email]")
+		tmp, doc, caption, url = utils.prepare_patch(
+			mail, text, url, "discord"
+		)
+		channel = self.get_channel(chat_id)
+
+		m = await channel.send(
+			content=caption,
+			file=discord.File(doc),
+			reference=discord.MessageReference(
+				guild_id=guild_id,
+				channel_id=chat_id,
+				message_id=reply_to
+			) if reply_to else None,
+
+			view=models.FullMessageBtn(url)
+		)
+
+		utils.remove_patch(tmp)
+		return m
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 16/26] discord: Add mail listener
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (14 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 15/26] discord: Add send lore email message functions Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 17/26] discord: Implement the mail Listener() class Muhammad Rizki
                   ` (10 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add the mail listener to receive new lore kernel email messages, then
send them to the Discord channel. If there is no new email message, the
listener will ignore it.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/mailer/__init__.py |   7 ++
 daemon/dscord/mailer/listener.py | 154 +++++++++++++++++++++++++++++++
 2 files changed, 161 insertions(+)
 create mode 100644 daemon/dscord/mailer/__init__.py
 create mode 100644 daemon/dscord/mailer/listener.py

diff --git a/daemon/dscord/mailer/__init__.py b/daemon/dscord/mailer/__init__.py
new file mode 100644
index 0000000..5d7e8d8
--- /dev/null
+++ b/daemon/dscord/mailer/__init__.py
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+from .listener import Listener
+from .listener import Mutexes
diff --git a/daemon/dscord/mailer/listener.py b/daemon/dscord/mailer/listener.py
new file mode 100644
index 0000000..a1c71ed
--- /dev/null
+++ b/daemon/dscord/mailer/listener.py
@@ -0,0 +1,154 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+# Copyright (C) 2022  Ammar Faizi <[email protected]>
+#
+
+import asyncio
+import traceback
+import shutil
+import re
+from apscheduler.schedulers.asyncio import AsyncIOScheduler
+from discord import File
+from discord import Message
+
+from dscord.gnuweeb import GWClient
+from atom.scraper import Scraper
+from atom import utils
+
+
+class Mutexes:
+	def __init__(self):
+		self.lock = asyncio.Lock()
+
+
+class Listener:
+	def __init__(
+                self,
+                client: "GWClient",
+                sched: "AsyncIOScheduler",
+		scraper: "Scraper",
+                mutexes: "Mutexes"
+        ):
+		self.client = client
+		self.sched = sched
+		self.scraper = scraper
+		self.mutexes = mutexes
+		self.db = client.db
+		self.isRunnerFixed = False
+		self.runner = None
+
+
+	def run(self):
+		#
+		# Execute __run() once to avoid high latency at
+		# initilization.
+		#
+		print("Initialize listener...\n")
+		self.sched.start()
+		self.runner = self.sched.add_job(func=self.__run)
+
+
+	async def __run(self):
+		print("[__run]: Running...")
+		for url in self.db.get_atom_urls():
+			try:
+				await self.__handle_atom_url(url)
+			except:
+				print(traceback.format_exc())
+
+		if not self.isRunnerFixed:
+			self.isRunnerFixed = True
+			self.runner = self.sched.add_job(
+				func=self.__run,
+				trigger="interval",
+				seconds=30,
+				misfire_grace_time=None,
+				max_instances=1
+			)
+
+
+	async def __handle_atom_url(self, url):
+		urls = await self.scraper.get_new_threads_urls(url)
+		for url in urls:
+			mail = await self.scraper.get_email_from_url(url)
+			await self.__handle_mail(url, mail)
+
+
+	async def __handle_mail(self, url, mail):
+		chats = self.db.get_broadcast_chats()
+		for chat in chats:
+			async with self.mutexes.lock:
+				should_wait = \
+				await self.__send_to_discord(url, mail,
+							chat[1], chat[2])
+
+			if should_wait:
+				await asyncio.sleep(1)
+
+
+	# @__must_hold(self.mutexes.lock)
+	async def __send_to_discord(self, url, mail, dc_guild_id, dc_chat_id):
+		email_msg_id = utils.get_email_msg_id(mail)
+		if not email_msg_id:
+			#
+			# It doesn't have a Message-Id.
+			# A malformed email. Skip!
+			#
+			return False
+
+		email_id = self.__get_email_id_sent(
+			email_msg_id=email_msg_id,
+			dc_chat_id=dc_chat_id
+		)
+		if not email_id:
+			#
+			# Email has already been sent to Discord.
+			# Skip!
+			#
+			return False
+
+		text, files, is_patch = utils.create_template(mail, "discord")
+		reply_to = self.get_discord_reply(mail, dc_chat_id)
+		url = str(re.sub(r"/raw$", "", url))
+
+		if is_patch:
+			m: Message = await self.client.send_patch_email(
+				mail, dc_guild_id, dc_chat_id, text, reply_to, url
+			)
+		else:
+			text = "#ml\n" + text
+			m: Message = await self.client.send_text_email(
+				dc_guild_id, dc_chat_id, text, reply_to, url
+			)
+
+		self.db.save_discord_mail(email_id, m.channel.id, m.id)
+		for d, f in files:
+			await m.reply(f"{d}/{f}", file=File(f))
+			await asyncio.sleep(1)
+
+		if files:
+			shutil.rmtree(str(files[0][0]))
+
+		return True
+
+
+	def __get_email_id_sent(self, email_msg_id, dc_chat_id):
+		email_id = self.db.save_email(email_msg_id)
+		if email_id:
+			return email_id
+
+		email_id = self.db.get_email_id(email_msg_id, dc_chat_id)
+		return email_id
+
+
+	def get_discord_reply(self, mail, dc_chat_id):
+		reply_to = mail.get("in-reply-to")
+		if not reply_to:
+			return None
+
+		reply_to = utils.extract_email_msg_id(reply_to)
+		if not reply_to:
+			return None
+
+		return self.db.get_reply_id(reply_to, dc_chat_id)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 17/26] discord: Implement the mail Listener() class
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (15 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 16/26] discord: Add mail listener Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 18/26] discord: Add @filters.lore_admin() decorator Muhammad Rizki
                   ` (9 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Use the mail Listener() class in the dc.py and add the scheduler for
the Listener() class works.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dc.py                                  | 20 +++++++++++++++++++
 daemon/dscord/gnuweeb/client.py               |  1 +
 .../dscord/gnuweeb/plugins/events/on_ready.py |  2 ++
 3 files changed, 23 insertions(+)

diff --git a/daemon/dc.py b/daemon/dc.py
index 9b86df2..5028e94 100644
--- a/daemon/dc.py
+++ b/daemon/dc.py
@@ -6,13 +6,24 @@
 import os
 from dotenv import load_dotenv
 from mysql import connector
+from apscheduler.schedulers.asyncio import AsyncIOScheduler
 
 from dscord.gnuweeb import GWClient
+from dscord.mailer import Listener
+from dscord.mailer import Mutexes
+from atom import Scraper
 
 
 def main():
 	load_dotenv("discord.env")
 
+	sched = AsyncIOScheduler(
+		job_defaults={
+			"max_instances": 3,
+			"misfire_grace_time": None
+		}
+	)
+
 	client = GWClient(
 		db_conn=connector.connect(
 			host=os.getenv("DB_HOST"),
@@ -21,6 +32,15 @@ def main():
 			database=os.getenv("DB_NAME")
 		)
 	)
+
+	mailer = Listener(
+		client=client,
+		sched=sched,
+		scraper=Scraper(),
+		mutexes=Mutexes()
+	)
+	client.mailer = mailer
+
 	client.run(os.getenv("DISCORD_TOKEN"), log_handler=None)
 
 
diff --git a/daemon/dscord/gnuweeb/client.py b/daemon/dscord/gnuweeb/client.py
index 2506ec3..03a1b8c 100644
--- a/daemon/dscord/gnuweeb/client.py
+++ b/daemon/dscord/gnuweeb/client.py
@@ -20,6 +20,7 @@ class GWClient(commands.Bot):
 		self.db = DB(db_conn)
 		intents = Intents.default()
 		intents.message_content = True
+		self.mailer = None
 		super().__init__(
 			command_prefix=["$", "."],
 			description="Just a bot for receiving lore emails.",
diff --git a/daemon/dscord/gnuweeb/plugins/events/on_ready.py b/daemon/dscord/gnuweeb/plugins/events/on_ready.py
index cb7de29..c93e8a0 100644
--- a/daemon/dscord/gnuweeb/plugins/events/on_ready.py
+++ b/daemon/dscord/gnuweeb/plugins/events/on_ready.py
@@ -13,6 +13,8 @@ class OnReady(commands.Cog):
 
 	@commands.Cog.listener()
 	async def on_ready(self):
+		self.bot.mailer.run()
+
 		t = "[ GNU/Weeb Bot is connected ]\n\n"
 		t += f"ID   : {self.bot.user.id}\n"
 		t += f"Name : {self.bot.user.display_name}\n"
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 18/26] discord: Add @filters.lore_admin() decorator
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (16 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 17/26] discord: Implement the mail Listener() class Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 19/26] discord: Add a list of atom URL slash command Muhammad Rizki
                   ` (8 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add a @filters.lore_admin() decorator to filter only the lore admin role
that can use the specific commands. With this, other users who don't
have the lore admin role cannot use the specific commands.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/gnuweeb/filters.py | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/daemon/dscord/gnuweeb/filters.py b/daemon/dscord/gnuweeb/filters.py
index 19f9445..eb54a8a 100644
--- a/daemon/dscord/gnuweeb/filters.py
+++ b/daemon/dscord/gnuweeb/filters.py
@@ -3,11 +3,37 @@
 # Copyright (C) 2022  Muhammad Rizki <[email protected]>
 #
 
-import discord
+
+# built-in/dev package imports
 import asyncio
 from typing import Any
 from functools import wraps
 
+# Discord imports
+import discord
+from discord import Interaction
+
+# gnuweeb package import
+from dscord import config
+
+
+def lore_admin(func):
+	@wraps(func)
+	async def callback(*args: Any, **kwargs: Any) -> Any:
+		i: "Interaction" = args[1]
+		user_roles = [role.id for role in i.user.roles]
+
+		if config.ADMIN_ROLE_ID not in user_roles:
+			return await i.response.send_message(
+				"Sorry, you don't have this permission\n"\
+				"Tell the server admin to add you lore admin role.",
+				ephemeral=True
+			)
+		if config.ADMIN_ROLE_ID in user_roles:
+			return await func(*args, **kwargs)
+
+	return callback
+
 
 def wait_on_limit(func):
 	@wraps(func)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 19/26] discord: Add a list of atom URL slash command
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (17 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 18/26] discord: Add @filters.lore_admin() decorator Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 20/26] discord: Add an add atom " Muhammad Rizki
                   ` (7 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add a `/atom list` slash command to get the list of atom URLs in the
database that is currently listening.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/gnuweeb/plugins/__init__.py     |  4 +-
 .../plugins/slash_commands/__init__.py        | 11 ++++++
 .../plugins/slash_commands/manage_atom.py     | 39 +++++++++++++++++++
 3 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 daemon/dscord/gnuweeb/plugins/slash_commands/__init__.py
 create mode 100644 daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py

diff --git a/daemon/dscord/gnuweeb/plugins/__init__.py b/daemon/dscord/gnuweeb/plugins/__init__.py
index cbec2b5..631d9ad 100644
--- a/daemon/dscord/gnuweeb/plugins/__init__.py
+++ b/daemon/dscord/gnuweeb/plugins/__init__.py
@@ -8,11 +8,13 @@ from discord.ext import commands
 
 from .events import Events
 from .basic_commands import BasicCommands
+from .slash_commands import SlashCommands
 
 
 class Plugins(
 	BasicCommands,
-	Events
+	Events,
+	SlashCommands
 ): pass
 
 
diff --git a/daemon/dscord/gnuweeb/plugins/slash_commands/__init__.py b/daemon/dscord/gnuweeb/plugins/slash_commands/__init__.py
new file mode 100644
index 0000000..0ed86b1
--- /dev/null
+++ b/daemon/dscord/gnuweeb/plugins/slash_commands/__init__.py
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+from .manage_atom import ManageAtomSC
+
+
+class SlashCommands(
+	ManageAtomSC,
+): pass
diff --git a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py
new file mode 100644
index 0000000..a4281c1
--- /dev/null
+++ b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+from discord.ext import commands
+from discord import Interaction
+from discord import app_commands
+
+from dscord.gnuweeb import filters
+
+
+class ManageAtomSC(commands.Cog):
+	atom = app_commands.Group(
+		name="atom",
+		description="Manage lore atom URL."
+	)
+
+	def __init__(self, bot) -> None:
+		self.bot = bot
+
+
+	@atom.command(
+		name="list",
+		description="List of lore atom URL."
+	)
+	@filters.lore_admin
+	async def list_atom(self, i: "Interaction"):
+		atoms = self.bot.db.get_atom_urls()
+		if len(atoms) == 0:
+			t = "Currently empty."
+			await i.response.send_message(t, ephemeral=True)
+			return
+
+		text = "List of atom URL that currently listened:\n"
+		for u,n in zip(atoms, range(1, len(atoms)+1)):
+			text += f"{n}. {u}\n"
+
+		await i.response.send_message(text, ephemeral=True)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 20/26] discord: Add an add atom slash command
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (18 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 19/26] discord: Add a list of atom URL slash command Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 21/26] discord: Add a delete " Muhammad Rizki
                   ` (6 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add `/add atom` to add an atom URL to the database for listening to a
new lore email message.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../plugins/slash_commands/manage_atom.py     | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py
index a4281c1..409e612 100644
--- a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py
+++ b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py
@@ -7,6 +7,7 @@ from discord.ext import commands
 from discord import Interaction
 from discord import app_commands
 
+from atom import utils
 from dscord.gnuweeb import filters
 
 
@@ -37,3 +38,26 @@ class ManageAtomSC(commands.Cog):
 			text += f"{n}. {u}\n"
 
 		await i.response.send_message(text, ephemeral=True)
+
+
+	@atom.command(
+		name="add",
+		description="Add lore atom URL for receiving lore emails."
+	)
+	@app_commands.describe(url='Lore atom URL.')
+	@filters.lore_admin
+	async def add_atom(self, i: "Interaction", url: str):
+		is_atom = await utils.is_atom_url(url)
+		if not is_atom:
+			t = "Invalid Atom URL."
+			await i.response.send_message(t, ephemeral=True)
+			return
+
+		inserted = self.bot.db.save_atom(url)
+		if inserted is None:
+			t = f"This URL already listened for new email."
+			await i.response.send_message(t, ephemeral=True)
+			return
+
+		t = f"Success add **{url}** for listening new email."
+		await i.response.send_message(t, ephemeral=True)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 21/26] discord: Add a delete atom slash command
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (19 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 20/26] discord: Add an add atom " Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 22/26] discord: Add channel_link() in the atom/utils.py Muhammad Rizki
                   ` (5 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add `/atom delete` to delete a specific atom URL in the database that is
currently listening new lore email message.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../plugins/slash_commands/manage_atom.py      | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py
index 409e612..e0a6b9e 100644
--- a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py
+++ b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_atom.py
@@ -61,3 +61,21 @@ class ManageAtomSC(commands.Cog):
 
 		t = f"Success add **{url}** for listening new email."
 		await i.response.send_message(t, ephemeral=True)
+
+
+	@atom.command(
+		name="delete",
+		description="Delete lore atom URL from receiving lore emails."
+	)
+	@app_commands.describe(url='Lore atom URL.')
+	@filters.lore_admin
+	async def del_atom(self, i: "Interaction", url: str):
+		success = self.bot.db.delete_atom(url)
+		if not success:
+			t = "Failed to delete atom URL\n"
+			t += "Maybe because already deleted or not exists."
+			await i.response.send_message(t, ephemeral=True)
+			return
+
+		t = f"Success delete **{url}** from receiving lore emails."
+		await i.response.send_message(t, ephemeral=True)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 22/26] discord: Add channel_link() in the atom/utils.py
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (20 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 21/26] discord: Add a delete " Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 23/26] discord: Add a list broadcast slash command Muhammad Rizki
                   ` (4 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add channel_link() to create a Discord channel URL with guild id and
channel id.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/atom/utils.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/daemon/atom/utils.py b/daemon/atom/utils.py
index bf1f0da..66f351f 100644
--- a/daemon/atom/utils.py
+++ b/daemon/atom/utils.py
@@ -306,3 +306,7 @@ def create_chat_link(chat: Chat):
 
 	chat_id_str = str(chat.id).replace("-100","")
 	return f"t.me/c/{chat_id_str}/1"
+
+
+def channel_link(guild_id: int, channel_id: int):
+	return f"https://discord.com/channels/{guild_id}/{channel_id}"
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 23/26] discord: Add a list broadcast slash command
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (21 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 22/26] discord: Add channel_link() in the atom/utils.py Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 24/26] discord: Add an add " Muhammad Rizki
                   ` (3 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add `/broadcast list` slash command to get the list of the current
Discord channel listening for a new lore email message.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../plugins/slash_commands/__init__.py        |  2 +
 .../slash_commands/manage_broadcast.py        | 41 +++++++++++++++++++
 2 files changed, 43 insertions(+)
 create mode 100644 daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py

diff --git a/daemon/dscord/gnuweeb/plugins/slash_commands/__init__.py b/daemon/dscord/gnuweeb/plugins/slash_commands/__init__.py
index 0ed86b1..a6d913c 100644
--- a/daemon/dscord/gnuweeb/plugins/slash_commands/__init__.py
+++ b/daemon/dscord/gnuweeb/plugins/slash_commands/__init__.py
@@ -4,8 +4,10 @@
 #
 
 from .manage_atom import ManageAtomSC
+from .manage_broadcast import ManageBroadcastSC
 
 
 class SlashCommands(
 	ManageAtomSC,
+	ManageBroadcastSC
 ): pass
diff --git a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py
new file mode 100644
index 0000000..db3d9e6
--- /dev/null
+++ b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2022  Muhammad Rizki <[email protected]>
+#
+
+from discord.ext import commands
+from discord import Interaction
+from discord import app_commands
+
+from dscord.gnuweeb import filters
+
+
+class ManageBroadcastSC(commands.Cog):
+	broadcast = app_commands.Group(
+		name="broadcast",
+		description="Manage broadcast channel."
+	)
+
+
+	def __init__(self, bot) -> None:
+		self.bot = bot
+
+
+	@broadcast.command(
+		name="list",
+		description="List of broadcast channel."
+	)
+	@filters.lore_admin
+	async def list_channel(self, i: "Interaction"):
+		chats = self.bot.db.get_broadcast_chats()
+		if len(chats) == 0:
+			t = "Currently empty."
+			await i.response.send_message(t, ephemeral=True)
+			return
+
+		text = "List of channels that will send email messages:\n"
+		for u,n in zip(chats, range(1, len(chats)+1)):
+			text += f"{n}. **{u[3]}**\n"
+			text += f"Link: {u[4]}\n\n"
+
+		await i.response.send_message(text, ephemeral=True)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 24/26] discord: Add an add broadcast slash command
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (22 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 23/26] discord: Add a list broadcast slash command Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 25/26] discord: Add a delete " Muhammad Rizki
                   ` (2 subsequent siblings)
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add `/broadcast add` to add the current Discord channel for listening to
new lore email messages.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../slash_commands/manage_broadcast.py        | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py
index db3d9e6..b9dd5e1 100644
--- a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py
+++ b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py
@@ -7,6 +7,7 @@ from discord.ext import commands
 from discord import Interaction
 from discord import app_commands
 
+from atom import utils
 from dscord.gnuweeb import filters
 
 
@@ -39,3 +40,28 @@ class ManageBroadcastSC(commands.Cog):
 			text += f"Link: {u[4]}\n\n"
 
 		await i.response.send_message(text, ephemeral=True)
+
+
+	@broadcast.command(
+		name="add",
+		description="Add broadcast channel for sending lore emails."
+	)
+	@filters.lore_admin
+	async def add_channel(self, i: "Interaction"):
+		inserted = self.bot.db.save_broadcast(
+			guild_id=i.guild_id,
+			channel_id=i.channel_id,
+			channel_name=i.channel.name,
+			channel_link=utils.channel_link(
+				guild_id=i.guild_id,
+				channel_id=i.channel_id
+			)
+		)
+
+		if inserted is None:
+			t = f"This channel already added for send email messages."
+			await i.response.send_message(t, ephemeral=True)
+			return
+
+		t = f"Success add this channel for send email messages."
+		await i.response.send_message(t, ephemeral=True)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 25/26] discord: Add a delete broadcast slash command
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (23 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 24/26] discord: Add an add " Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-01 13:03 ` [PATCH v1 26/26] discord: Change the on_ready message Muhammad Rizki
  2022-10-03 12:48 ` [PATCH v1 00/26] The complete version of the Discord bot Ammar Faizi
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add `/broadcast delete` to delete current Discord channel from listening
new lore email message.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 .../plugins/slash_commands/manage_broadcast.py  | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py
index b9dd5e1..c04560d 100644
--- a/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py
+++ b/daemon/dscord/gnuweeb/plugins/slash_commands/manage_broadcast.py
@@ -65,3 +65,20 @@ class ManageBroadcastSC(commands.Cog):
 
 		t = f"Success add this channel for send email messages."
 		await i.response.send_message(t, ephemeral=True)
+
+
+	@broadcast.command(
+		name="delete",
+		description="Delete broadcast channel from sending email messages."
+	)
+	@filters.lore_admin
+	async def del_channel(self, i: "Interaction"):
+		success = self.bot.db.delete_broadcast(i.channel_id)
+		if not success:
+			t = "Failed to delete this channel\n"
+			t += "Maybe because already deleted or not exists."
+			await i.response.send_message(t, ephemeral=True)
+			return
+
+		t = f"Success delete this channel from sending email messages."
+		await i.response.send_message(t, ephemeral=True)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v1 26/26] discord: Change the on_ready message
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (24 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 25/26] discord: Add a delete " Muhammad Rizki
@ 2022-10-01 13:03 ` Muhammad Rizki
  2022-10-03 12:48 ` [PATCH v1 00/26] The complete version of the Discord bot Ammar Faizi
  26 siblings, 0 replies; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-01 13:03 UTC (permalink / raw)
  To: Ammar Faizi
  Cc: Muhammad Rizki, Alviro Iskandar Setiawan, GNU/Weeb Mailing List

Add a tips message on the on_ready event, so the author of the bot is
know what to do when the bot first starts.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 daemon/dscord/gnuweeb/plugins/events/on_ready.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/daemon/dscord/gnuweeb/plugins/events/on_ready.py b/daemon/dscord/gnuweeb/plugins/events/on_ready.py
index c93e8a0..4f25764 100644
--- a/daemon/dscord/gnuweeb/plugins/events/on_ready.py
+++ b/daemon/dscord/gnuweeb/plugins/events/on_ready.py
@@ -14,10 +14,13 @@ class OnReady(commands.Cog):
 	@commands.Cog.listener()
 	async def on_ready(self):
 		self.bot.mailer.run()
+		prefix = self.bot.command_prefix[0]
 
 		t = "[ GNU/Weeb Bot is connected ]\n\n"
 		t += f"ID   : {self.bot.user.id}\n"
 		t += f"Name : {self.bot.user.display_name}\n"
 		t += f"Tags : {self.bot.user}\n\n"
-		t += "Ready to get the latest of lore kernel emails."
+		t += f"Send `{prefix}sync` message to the Discord channel "
+		t += "where the bot is running.\n"
+
 		print(t)
-- 
Muhammad Rizki


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
                   ` (25 preceding siblings ...)
  2022-10-01 13:03 ` [PATCH v1 26/26] discord: Change the on_ready message Muhammad Rizki
@ 2022-10-03 12:48 ` Ammar Faizi
  2022-10-03 13:04   ` Muhammad Rizki
                     ` (2 more replies)
  26 siblings, 3 replies; 39+ messages in thread
From: Ammar Faizi @ 2022-10-03 12:48 UTC (permalink / raw)
  To: Muhammad Rizki; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List

On 10/1/22 8:03 PM, Muhammad Rizki wrote:
> How to use:
> 1. Execute the db.sql file in the daemon directory,
> 2. Setup .env file, the example is there with suffix .example, this
>     file name must remove the suffix name .example,
> 3. Set up the config.py in each bot directory, such as dscord and
>     telegram. The example is there with suffix .example & the file name
>     must remove suffix name .example,
> 4. Run `pip3 install -r requirements.txt` in each bot directory,
> 5. STORAGE_DIR env value must `storage` to make it work fine,
> 6. Run the bot by `python3 dc.py` or `python3 tg.py`.
> 
> Both tested and worked fine. Please give it a test if I still forgot
> something like in the past, thanks!

Hi,

I have tested the bot, it runs well when it delivers an email that
doesn't have an attachment, but sometimes it is broken. See the
traces below. Also, the files in storage dir are not deleted. Do
you know what may be going wrong here?

Files are not deleted:

ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ ls dscord/storage -l
total 0
drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  78 Sep  3 17:25 23035eeb480f2b3501ba0841ef10ce3f
drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Oct  3 19:42 6766c45fa800d71173893158b2c7d640
drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:22 78380c23529749c280e4cca46f7519c9
drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 a23e986acc2c75d08a3e98377f06bbfe
drwxrwxr-x 1 ammarfaizi2 ammarfaizi2 356 Sep  3 17:22 b241bd7c932c70e6a81d107da019cb67
drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Sep  3 17:25 bcaac8364eaf04951d504faa1f1df826
drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 c36cdede05b536d395c5b55dbae92288
ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$


--------------------------------------------

ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ python3 dc.py
Initialize listener...

[ GNU/Weeb Bot is connected ]

ID   : 1015428932612403221
Name : GNUWeeb2
Tags : GNUWeeb2#3452

Send `$sync` message to the Discord channel where the bot is running.

[__run]: Running...
[send_text_email]
Traceback (most recent call last):
   File "/home/ammarfaizi2/app/lore-daemon.dev/daemon/dscord/mailer/listener.py", line 56, in __run
     await self.__handle_atom_url(url)
   File "/home/ammarfaizi2/app/lore-daemon.dev/daemon/dscord/mailer/listener.py", line 75, in __handle_atom_url
     await self.__handle_mail(url, mail)
   File "/home/ammarfaizi2/app/lore-daemon.dev/daemon/dscord/mailer/listener.py", line 83, in __handle_mail
     await self.__send_to_discord(url, mail,
   File "/home/ammarfaizi2/app/lore-daemon.dev/daemon/dscord/mailer/listener.py", line 127, in __send_to_discord
     await m.reply(f"{d}/{f}", file=File(f))
   File "/home/ammarfaizi2/.local/lib/python3.10/site-packages/discord/file.py", line 97, in __init__
     self.fp = open(fp, 'rb')
FileNotFoundError: [Errno 2] No such file or directory: 'config'

[__run]: Running...


---------------------------------------

My discord.env is:
# Input your Discord bot token below
DISCORD_TOKEN=<snip>

# Input your MySQL connection below
DB_HOST=127.0.0.1
DB_USER=<snip>
DB_PASS=<snip>
DB_NAME=lored_testing

# Storage directory to save patch files
STORAGE_DIR=storage

---------------------------------------

My config.py is:
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2022  Muhammad Rizki <[email protected]>
#

# Paste the admin role ID below
# to filter only admin who can
# access add/delete lore commands.
ADMIN_ROLE_ID = 865885118878711828

# The activity name like "Playing Genshin Impact"
# you set the value as "Genshin Impact"
ACTIVITY_NAME = "aaaaaaaaaaaa"


-- 
Ammar Faizi

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 12:48 ` [PATCH v1 00/26] The complete version of the Discord bot Ammar Faizi
@ 2022-10-03 13:04   ` Muhammad Rizki
  2022-10-03 13:13     ` Ammar Faizi
  2022-10-03 13:12   ` Muhammad Rizki
  2022-10-03 23:12   ` Alviro Iskandar Setiawan
  2 siblings, 1 reply; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-03 13:04 UTC (permalink / raw)
  To: Ammar Faizi; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List

On 03/10/2022 19.48, Ammar Faizi wrote:
> Hi,
> 
> I have tested the bot, it runs well when it delivers an email that
> doesn't have an attachment, but sometimes it is broken. See the
> traces below. Also, the files in storage dir are not deleted. Do
> you know what may be going wrong here?
> 
> Files are not deleted:
> 
> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ ls dscord/storage -l
> total 0
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  78 Sep  3 17:25 
> 23035eeb480f2b3501ba0841ef10ce3f
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Oct  3 19:42 
> 6766c45fa800d71173893158b2c7d640
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:22 
> 78380c23529749c280e4cca46f7519c9
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 
> a23e986acc2c75d08a3e98377f06bbfe
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2 356 Sep  3 17:22 
> b241bd7c932c70e6a81d107da019cb67
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Sep  3 17:25 
> bcaac8364eaf04951d504faa1f1df826
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 
> c36cdede05b536d395c5b55dbae92288
> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$
> 

Hi,

We know this issue has been going on for a long time, and we still 
haven't figured out how to solve it, maybe because it wasn't mutexed 
first or something. I haven't tested it for the lock mutex file deletion 
yet.

> "/home/ammarfaizi2/.local/lib/python3.10/site-packages/discord/file.py", 
> line 97, in __init__
>      self.fp = open(fp, 'rb')
> FileNotFoundError: [Errno 2] No such file or directory: 'config'
> 

This issue may be because the lore email patch file is not yet in the 
storage directory.

Make sure you run a python command in the daemon/ directory.
- cd daemon
- python3 dc.py

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 12:48 ` [PATCH v1 00/26] The complete version of the Discord bot Ammar Faizi
  2022-10-03 13:04   ` Muhammad Rizki
@ 2022-10-03 13:12   ` Muhammad Rizki
  2022-10-03 13:13     ` Ammar Faizi
  2022-10-03 23:12   ` Alviro Iskandar Setiawan
  2 siblings, 1 reply; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-03 13:12 UTC (permalink / raw)
  To: Ammar Faizi; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List

On 03/10/2022 19.48, Ammar Faizi wrote:
> "/home/ammarfaizi2/.local/lib/python3.10/site-packages/discord/file.py", 
> line 97, in __init__
>      self.fp = open(fp, 'rb')
> FileNotFoundError: [Errno 2] No such file or directory: 'config'

Currently, I'm testing this. Wait a moment.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 13:04   ` Muhammad Rizki
@ 2022-10-03 13:13     ` Ammar Faizi
  0 siblings, 0 replies; 39+ messages in thread
From: Ammar Faizi @ 2022-10-03 13:13 UTC (permalink / raw)
  To: Muhammad Rizki; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List

On 10/3/22 8:04 PM, Muhammad Rizki wrote:
> We know this issue has been going on for a long time, and we still
> haven't figured out how to solve it, maybe because it wasn't mutexed
> first or something. I haven't tested it for the lock mutex file deletion
> yet.

I honestly don't see the race condition that leads to this issue. Not
sure which function call should be protected by a mutex. Do you have
the race condition scenario?

>> "/home/ammarfaizi2/.local/lib/python3.10/site-packages/discord/file.py",
>> line 97, in __init__
>>      self.fp = open(fp, 'rb')
>> FileNotFoundError: [Errno 2] No such file or directory: 'config'
>>
> 
> This issue may be because the lore email patch file is not yet in the
> storage directory.
> 
> Make sure you run a python command in the daemon/ directory.
> - cd daemon
> - python3 dc.py

I have already been in daemon/ directory. See my previous email:

ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ python3 dc.py

-- 
Ammar Faizi

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 13:12   ` Muhammad Rizki
@ 2022-10-03 13:13     ` Ammar Faizi
  0 siblings, 0 replies; 39+ messages in thread
From: Ammar Faizi @ 2022-10-03 13:13 UTC (permalink / raw)
  To: Muhammad Rizki; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List

On 10/3/22 8:12 PM, Muhammad Rizki wrote:
> On 03/10/2022 19.48, Ammar Faizi wrote:
>> "/home/ammarfaizi2/.local/lib/python3.10/site-packages/discord/file.py", line 97, in __init__
>>      self.fp = open(fp, 'rb')
>> FileNotFoundError: [Errno 2] No such file or directory: 'config'
> 
> Currently, I'm testing this. Wait a moment.

OK.

-- 
Ammar Faizi

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 12:48 ` [PATCH v1 00/26] The complete version of the Discord bot Ammar Faizi
  2022-10-03 13:04   ` Muhammad Rizki
  2022-10-03 13:12   ` Muhammad Rizki
@ 2022-10-03 23:12   ` Alviro Iskandar Setiawan
  2022-10-03 23:14     ` Ammar Faizi
  2022-10-03 23:18     ` Muhammad Rizki
  2 siblings, 2 replies; 39+ messages in thread
From: Alviro Iskandar Setiawan @ 2022-10-03 23:12 UTC (permalink / raw)
  To: Ammar Faizi; +Cc: Muhammad Rizki, GNU/Weeb Mailing List

On Mon, Oct 3, 2022 at 7:48 PM Ammar Faizi wrote:
> Files are not deleted:
>
> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ ls dscord/storage -l
> total 0
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  78 Sep  3 17:25 23035eeb480f2b3501ba0841ef10ce3f
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Oct  3 19:42 6766c45fa800d71173893158b2c7d640
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:22 78380c23529749c280e4cca46f7519c9
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 a23e986acc2c75d08a3e98377f06bbfe
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2 356 Sep  3 17:22 b241bd7c932c70e6a81d107da019cb67
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Sep  3 17:25 bcaac8364eaf04951d504faa1f1df826
> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 c36cdede05b536d395c5b55dbae92288
> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$

bang, only 1 file from 3rd Oct, the rest are all old files from a
month ago, look at the date

-- Viro

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 23:12   ` Alviro Iskandar Setiawan
@ 2022-10-03 23:14     ` Ammar Faizi
  2022-10-03 23:18     ` Muhammad Rizki
  1 sibling, 0 replies; 39+ messages in thread
From: Ammar Faizi @ 2022-10-03 23:14 UTC (permalink / raw)
  To: Alviro Iskandar Setiawan; +Cc: Muhammad Rizki, GNU/Weeb Mailing List

On 10/4/22 6:12 AM, Alviro Iskandar Setiawan wrote:
> On Mon, Oct 3, 2022 at 7:48 PM Ammar Faizi wrote:
>> Files are not deleted:
>>
>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ ls dscord/storage -l
>> total 0
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  78 Sep  3 17:25 23035eeb480f2b3501ba0841ef10ce3f
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Oct  3 19:42 6766c45fa800d71173893158b2c7d640
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:22 78380c23529749c280e4cca46f7519c9
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 a23e986acc2c75d08a3e98377f06bbfe
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2 356 Sep  3 17:22 b241bd7c932c70e6a81d107da019cb67
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Sep  3 17:25 bcaac8364eaf04951d504faa1f1df826
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 c36cdede05b536d395c5b55dbae92288
>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$
> 
> bang, only 1 file from 3rd Oct, the rest are all old files from a
> month ago, look at the date

That being said, this issue has been there forever since a time
long ago. Even before the Discord bot exists.

-- 
Ammar Faizi

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 23:12   ` Alviro Iskandar Setiawan
  2022-10-03 23:14     ` Ammar Faizi
@ 2022-10-03 23:18     ` Muhammad Rizki
  2022-10-03 23:22       ` Alviro Iskandar Setiawan
  1 sibling, 1 reply; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-03 23:18 UTC (permalink / raw)
  To: Alviro Iskandar Setiawan, Ammar Faizi; +Cc: GNU/Weeb Mailing List

On 04/10/2022 06.12, Alviro Iskandar Setiawan wrote:
> On Mon, Oct 3, 2022 at 7:48 PM Ammar Faizi wrote:
>> Files are not deleted:
>>
>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ ls dscord/storage -l
>> total 0
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  78 Sep  3 17:25 23035eeb480f2b3501ba0841ef10ce3f
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Oct  3 19:42 6766c45fa800d71173893158b2c7d640
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:22 78380c23529749c280e4cca46f7519c9
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 a23e986acc2c75d08a3e98377f06bbfe
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2 356 Sep  3 17:22 b241bd7c932c70e6a81d107da019cb67
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Sep  3 17:25 bcaac8364eaf04951d504faa1f1df826
>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 c36cdede05b536d395c5b55dbae92288
>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$
> 
> bang, only 1 file from 3rd Oct, the rest are all old files from a
> month ago, look at the date
> 

Yes, this issue has already been a long time not fixed, because, in the 
past, I still don't know what caused it. Now, I think I see the problem. 
I've patched it and tested it. Wait until I send new PATCH email, thanks.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 23:18     ` Muhammad Rizki
@ 2022-10-03 23:22       ` Alviro Iskandar Setiawan
  2022-10-03 23:31         ` Ammar Faizi
  2022-10-03 23:33         ` Muhammad Rizki
  0 siblings, 2 replies; 39+ messages in thread
From: Alviro Iskandar Setiawan @ 2022-10-03 23:22 UTC (permalink / raw)
  To: Muhammad Rizki; +Cc: Ammar Faizi, GNU/Weeb Mailing List

On Tue, Oct 4, 2022 at 6:18 AM Muhammad Rizki wrote:
> On 04/10/2022 06.12, Alviro Iskandar Setiawan wrote:
>> On Mon, Oct 3, 2022 at 7:48 PM Ammar Faizi wrote:
>>> Files are not deleted:
>>>
>>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ ls dscord/storage -l
>>> total 0
>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  78 Sep  3 17:25 23035eeb480f2b3501ba0841ef10ce3f
>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Oct  3 19:42 6766c45fa800d71173893158b2c7d640
>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:22 78380c23529749c280e4cca46f7519c9
>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 a23e986acc2c75d08a3e98377f06bbfe
>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2 356 Sep  3 17:22 b241bd7c932c70e6a81d107da019cb67
>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Sep  3 17:25 bcaac8364eaf04951d504faa1f1df826
>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 c36cdede05b536d395c5b55dbae92288
>>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$
>>
>> bang, only 1 file from 3rd Oct, the rest are all old files from a
>> month ago, look at the date
>>
>
> Yes, this issue has already been a long time not fixed, because, in the
> past, I still don't know what caused it. Now, I think I see the problem.
> I've patched it and tested it. Wait until I send new PATCH email, thanks.

the error Ammar reported could be the reason why the files are not
deleted, because if you hit an error, the code next to it won't be
executed, for ex:

aaa() # error here
bbb() # this doesn't get executed

you must use finally to handle this:

try:
    aaa() # error here
execpt:
    pass
finally:
    bbb() # it always gets executed

but idk, i didn't investigate, just speculate

-- Viro

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 23:22       ` Alviro Iskandar Setiawan
@ 2022-10-03 23:31         ` Ammar Faizi
  2022-10-03 23:33         ` Muhammad Rizki
  1 sibling, 0 replies; 39+ messages in thread
From: Ammar Faizi @ 2022-10-03 23:31 UTC (permalink / raw)
  To: Alviro Iskandar Setiawan, Muhammad Rizki; +Cc: GNU/Weeb Mailing List

On 10/4/22 6:22 AM, Alviro Iskandar Setiawan wrote:
> On Tue, Oct 4, 2022 at 6:18 AM Muhammad Rizki wrote:
>> On 04/10/2022 06.12, Alviro Iskandar Setiawan wrote:
>>> On Mon, Oct 3, 2022 at 7:48 PM Ammar Faizi wrote:
>>>> Files are not deleted:
>>>>
>>>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ ls dscord/storage -l
>>>> total 0
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  78 Sep  3 17:25 23035eeb480f2b3501ba0841ef10ce3f
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Oct  3 19:42 6766c45fa800d71173893158b2c7d640
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:22 78380c23529749c280e4cca46f7519c9
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 a23e986acc2c75d08a3e98377f06bbfe
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2 356 Sep  3 17:22 b241bd7c932c70e6a81d107da019cb67
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Sep  3 17:25 bcaac8364eaf04951d504faa1f1df826
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 c36cdede05b536d395c5b55dbae92288
>>>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$
>>>
>>> bang, only 1 file from 3rd Oct, the rest are all old files from a
>>> month ago, look at the date
>>>
>>
>> Yes, this issue has already been a long time not fixed, because, in the
>> past, I still don't know what caused it. Now, I think I see the problem.
>> I've patched it and tested it. Wait until I send new PATCH email, thanks.
> 
> the error Ammar reported could be the reason why the files are not
> deleted, because if you hit an error, the code next to it won't be
> executed, for ex:
> 
> aaa() # error here
> bbb() # this doesn't get executed
> 
> you must use finally to handle this:
> 
> try:
>      aaa() # error here
> execpt:
>      pass
> finally:
>      bbb() # it always gets executed
> 
> but idk, i didn't investigate, just speculate

I think we should fix the error in the first place. But I am fine
with this cleanup strategy if you have addressed the error.

I honestly don't like this approach, much better using some kind
of return value check and goto just like I usually do in C. But
we are not talking about C, so let's take the Python try+finally
approach.

-- 
Ammar Faizi

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 23:22       ` Alviro Iskandar Setiawan
  2022-10-03 23:31         ` Ammar Faizi
@ 2022-10-03 23:33         ` Muhammad Rizki
  2022-10-03 23:36           ` Ammar Faizi
  1 sibling, 1 reply; 39+ messages in thread
From: Muhammad Rizki @ 2022-10-03 23:33 UTC (permalink / raw)
  To: Alviro Iskandar Setiawan; +Cc: Ammar Faizi, GNU/Weeb Mailing List

On 04/10/2022 06.22, Alviro Iskandar Setiawan wrote:
> On Tue, Oct 4, 2022 at 6:18 AM Muhammad Rizki wrote:
>> On 04/10/2022 06.12, Alviro Iskandar Setiawan wrote:
>>> On Mon, Oct 3, 2022 at 7:48 PM Ammar Faizi wrote:
>>>> Files are not deleted:
>>>>
>>>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ ls dscord/storage -l
>>>> total 0
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  78 Sep  3 17:25 23035eeb480f2b3501ba0841ef10ce3f
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Oct  3 19:42 6766c45fa800d71173893158b2c7d640
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:22 78380c23529749c280e4cca46f7519c9
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 a23e986acc2c75d08a3e98377f06bbfe
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2 356 Sep  3 17:22 b241bd7c932c70e6a81d107da019cb67
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Sep  3 17:25 bcaac8364eaf04951d504faa1f1df826
>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 c36cdede05b536d395c5b55dbae92288
>>>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$
>>>
>>> bang, only 1 file from 3rd Oct, the rest are all old files from a
>>> month ago, look at the date
>>>
>>
>> Yes, this issue has already been a long time not fixed, because, in the
>> past, I still don't know what caused it. Now, I think I see the problem.
>> I've patched it and tested it. Wait until I send new PATCH email, thanks.
> 
> the error Ammar reported could be the reason why the files are not
> deleted, because if you hit an error, the code next to it won't be
> executed, for ex:
> 
> aaa() # error here
> bbb() # this doesn't get executed
> 
> you must use finally to handle this:
> 
> try:
>      aaa() # error here
> execpt:
>      pass
> finally:
>      bbb() # it always gets executed
> 
> but idk, i didn't investigate, just speculate
> 
> -- Viro

At first, I want to try what I just patched here then you guys review 
it, if it still bug, then I use the Python try:except: statement. I 
think that statement is not necessary.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v1 00/26] The complete version of the Discord bot
  2022-10-03 23:33         ` Muhammad Rizki
@ 2022-10-03 23:36           ` Ammar Faizi
  0 siblings, 0 replies; 39+ messages in thread
From: Ammar Faizi @ 2022-10-03 23:36 UTC (permalink / raw)
  To: Muhammad Rizki, Alviro Iskandar Setiawan; +Cc: GNU/Weeb Mailing List

On 10/4/22 6:33 AM, Muhammad Rizki wrote:
> On 04/10/2022 06.22, Alviro Iskandar Setiawan wrote:
>> On Tue, Oct 4, 2022 at 6:18 AM Muhammad Rizki wrote:
>>> On 04/10/2022 06.12, Alviro Iskandar Setiawan wrote:
>>>> On Mon, Oct 3, 2022 at 7:48 PM Ammar Faizi wrote:
>>>>> Files are not deleted:
>>>>>
>>>>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$ ls dscord/storage -l
>>>>> total 0
>>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  78 Sep  3 17:25 23035eeb480f2b3501ba0841ef10ce3f
>>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Oct  3 19:42 6766c45fa800d71173893158b2c7d640
>>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:22 78380c23529749c280e4cca46f7519c9
>>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 a23e986acc2c75d08a3e98377f06bbfe
>>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2 356 Sep  3 17:22 b241bd7c932c70e6a81d107da019cb67
>>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2  12 Sep  3 17:25 bcaac8364eaf04951d504faa1f1df826
>>>>> drwxrwxr-x 1 ammarfaizi2 ammarfaizi2   0 Sep  3 17:23 c36cdede05b536d395c5b55dbae92288
>>>>> ammarfaizi2@integral2:~/app/lore-daemon.dev/daemon$
>>>>
>>>> bang, only 1 file from 3rd Oct, the rest are all old files from a
>>>> month ago, look at the date
>>>>
>>>
>>> Yes, this issue has already been a long time not fixed, because, in the
>>> past, I still don't know what caused it. Now, I think I see the problem.
>>> I've patched it and tested it. Wait until I send new PATCH email, thanks.
>> 
>> the error Ammar reported could be the reason why the files are not
>> deleted, because if you hit an error, the code next to it won't be
>> executed, for ex:
>> 
>> aaa() # error here
>> bbb() # this doesn't get executed
>> 
>> you must use finally to handle this:
>> 
>> try:
>>      aaa() # error here
>> execpt:
>>      pass
>> finally:
>>      bbb() # it always gets executed
>> 
>> but idk, i didn't investigate, just speculate
>> 
>> -- Viro
> 
> At first, I want to try what I just patched here then you guys review 
> it, if it still bug, then I use the Python try:except: statement. I 
> think that statement is not necessary.

Ditto, let's wait for the next version of this series and see if this
issue gets fixed. Good morning everyone, have a nice day!

/me heading to bathroom

-- 
Ammar Faizi

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2022-10-03 23:36 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-10-01 13:03 [PATCH v1 00/26] The complete version of the Discord bot Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 01/26] discord: Add get_atom_urls() to get the list of atom URLs Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 02/26] Fix the storage management after the refactor was happened Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 03/26] discord: Add get_broadcast_chats() to get the list of broadcast chats Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 04/26] discord: Add get_email_id() in getter directory Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 05/26] discord: Add get_reply_id() " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 06/26] discord: Inherit Getter() class to the DBMethods() class Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 07/26] discord: Add delete_atom() in deletion directory Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 08/26] discord: Add delete_broadcast() " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 09/26] discord: Inherit the Deletion() class to the DBMethods() class Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 10/26] discord: Inherit the DBMethods() class to the DB() class Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 11/26] discord: Use the created " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 12/26] telegram: Rename some utility functions Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 13/26] discord: Add a FullMessageBtn() class in models Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 14/26] discord: Add filters.wait_on_limit() decorator Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 15/26] discord: Add send lore email message functions Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 16/26] discord: Add mail listener Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 17/26] discord: Implement the mail Listener() class Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 18/26] discord: Add @filters.lore_admin() decorator Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 19/26] discord: Add a list of atom URL slash command Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 20/26] discord: Add an add atom " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 21/26] discord: Add a delete " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 22/26] discord: Add channel_link() in the atom/utils.py Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 23/26] discord: Add a list broadcast slash command Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 24/26] discord: Add an add " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 25/26] discord: Add a delete " Muhammad Rizki
2022-10-01 13:03 ` [PATCH v1 26/26] discord: Change the on_ready message Muhammad Rizki
2022-10-03 12:48 ` [PATCH v1 00/26] The complete version of the Discord bot Ammar Faizi
2022-10-03 13:04   ` Muhammad Rizki
2022-10-03 13:13     ` Ammar Faizi
2022-10-03 13:12   ` Muhammad Rizki
2022-10-03 13:13     ` Ammar Faizi
2022-10-03 23:12   ` Alviro Iskandar Setiawan
2022-10-03 23:14     ` Ammar Faizi
2022-10-03 23:18     ` Muhammad Rizki
2022-10-03 23:22       ` Alviro Iskandar Setiawan
2022-10-03 23:31         ` Ammar Faizi
2022-10-03 23:33         ` Muhammad Rizki
2022-10-03 23:36           ` Ammar Faizi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox