From 8feda11051d8bbd75eaa5877780f9d9188fc5351 Mon Sep 17 00:00:00 2001 From: Alexander Zveruk Date: Wed, 20 May 2020 22:41:48 +0300 Subject: [PATCH 1/5] wip --- tg/config.py | 1 + tg/controllers/__init__.py | 59 ++++++++++++++++++++++++++------------ tg/main.py | 12 ++++++++ tg/models/__init__.py | 27 ++++++++++++++++- 4 files changed, 79 insertions(+), 20 deletions(-) diff --git a/tg/config.py b/tg/config.py index 0aedd41..9e7a99c 100644 --- a/tg/config.py +++ b/tg/config.py @@ -8,6 +8,7 @@ DEFAULT_FILES = os.path.expanduser("~/.cache/tg/") max_download_size = "10MB" record_cmd = None long_msg_cmd = "vim -c 'startinsert' {file_path}" +editor = os.environ.get("EDITOR", "vi") def get_cfg(config=DEFAULT_CONFIG): diff --git a/tg/controllers/__init__.py b/tg/controllers/__init__.py index 868e8e1..ba78964 100644 --- a/tg/controllers/__init__.py +++ b/tg/controllers/__init__.py @@ -92,7 +92,7 @@ class Controller: log.exception("Error happened in main loop") def download_current_file(self): - msg = MsgProxy(self.model.current_msg()) + msg = MsgProxy(self.model.current_msg) log.debug("Downloading msg: %s", msg.msg) file_id = msg.file_id if file_id: @@ -105,12 +105,11 @@ class Controller: log.info("Downloaded: file_id=%s", file_id) def open_current_msg(self): - msg = MsgProxy(self.model.current_msg()) + msg = MsgProxy(self.model.current_msg) log.info("Open msg: %s", msg.msg) if msg.is_text: - text = msg["content"]["text"]["text"] with NamedTemporaryFile("w", suffix=".txt") as f: - f.write(text) + f.write(msg.text_content) f.flush() with suspend(self.view) as s: s.open_file(f.name) @@ -122,19 +121,38 @@ class Controller: log.info("Opening file: %s", path) s.open_file(path) - def write_long_msg(self): - file_path = "/tmp/tg-msg.txt" - with suspend(self.view) as s: - s.call(config.long_msg_cmd.format(file_path=file_path)) - if not os.path.isfile(file_path): + def edit_msg(self): + msg = MsgProxy(self.model.current_msg) + log.info("Editing msg: %s", msg.msg) + if not self.model.is_me(msg.sender_id): + log.warning("Can't edit other user message") return - with open(file_path) as f: - msg = f.read().strip() - os.remove(file_path) - if msg: - self.model.send_message(text=msg) - with self.lock: - self.view.status.draw("Message sent") + if not msg.is_text: + log.warning("Can't edit not text message") + return + + with NamedTemporaryFile("r+", suffix=".txt") as f, suspend( + self.view + ) as s: + f.write(msg.text_content) + f.flush() + s.call(f"{config.editor} {f.name}") + f.seek(0) + if msg := f.read().strip(): + self.model.edit_message(text=msg) + with self.lock: + self.view.status.draw("Message edited") + + def write_long_msg(self): + with NamedTemporaryFile("r+", suffix=".txt") as f, suspend( + self.view + ) as s: + s.call(config.long_msg_cmd.format(file_path=f.name)) + f.seek(0) + if msg := f.read().strip(): + self.model.send_message(text=msg) + with self.lock: + self.view.status.draw("Message sent") def resize_handler(self, signum, frame): curses.endwin() @@ -221,16 +239,19 @@ class Controller: elif keys == "/": # search pass + elif keys == "gg": # move to the top pass + elif keys == "e": - # edit msg - pass + self.edit_msg() + elif keys == "r": # reply to this msg # print to status line pass + elif keys in ("i", "a"): # write new message msg = self.view.status.get_input() @@ -386,7 +407,7 @@ class Controller: return # notify - if msg.sender_id == self.model.get_me()["id"]: + if self.model.is_me(msg["sender_user_id"]): return user = self.model.users.get_user(msg.sender_id) name = f"{user['first_name']} {user['last_name']}" diff --git a/tg/main.py b/tg/main.py index f2e4c64..b8cf275 100644 --- a/tg/main.py +++ b/tg/main.py @@ -108,6 +108,18 @@ class TelegramApi(Telegram): } return self._send_data(data) + def edit_message(self, chat_id: int, message_id: int, msg: str): + data = { + "@type": "editMessageText", + "message_id": message_id, + "chat_id": chat_id, + "input_message_content": { + "@type": "inputMessageText", + "text": {"@type": "formattedText", "text": msg}, + }, + } + return self._send_data(data) + def toggle_chat_is_marked_as_unread( self, chat_id: int, is_marked_as_unread: bool ): diff --git a/tg/models/__init__.py b/tg/models/__init__.py index 568d0ca..37908a6 100644 --- a/tg/models/__init__.py +++ b/tg/models/__init__.py @@ -18,6 +18,9 @@ class Model: def get_me(self): return self.users.get_me() + def is_me(self, user_id: int) -> bool: + return self.get_me()["id"] == user_id + def get_user(self, user_id): return self.users.get_user(user_id) @@ -42,7 +45,8 @@ class Model: limit = offset + page_size return self.msgs.fetch_msgs(chat_id, offset=offset, limit=limit) - def current_msg(self): + @property + def current_msg(self) -> Dict[str, Any]: chat_id = self.chats.id_by_index(self.current_chat) if chat_id is None: return {} @@ -50,6 +54,10 @@ class Model: log.info("current-msg: %s", current_msg) return self.msgs.msgs[chat_id][current_msg] + @property + def current_msg_id(self) -> int: + return self.current_msg["id"] + def jump_bottom(self): chat_id = self.chats.id_by_index(self.current_chat) return self.msgs.jump_bottom(chat_id) @@ -103,6 +111,11 @@ class Model: self.msgs.send_message(chat_id, text) return True + def edit_message(self, text: str) -> bool: + if chat_id := self.chats.id_by_index(self.current_chat): + return self.msgs.edit_message(chat_id, self.current_msg_id, text) + return False + def delete_msg(self) -> bool: chat_id = self.chats.id_by_index(self.current_chat) if chat_id: @@ -322,6 +335,18 @@ class MsgModel: if i < len(self.msgs[chat_id]) ] + def edit_message(self, chat_id: int, message_id: int, text: str) -> bool: + log.info("Editing msg") + result = self.tg.edit_message(chat_id, message_id, text) + + result.wait() + if result.error: + log.info(f"send message error: {result.error_info}") + return False + else: + log.info(f"message has been sent: {result.update}") + return True + def send_message(self, chat_id: int, text: str) -> None: log.info("Sending msg") result = self.tg.send_message(chat_id=chat_id, text=text) From c16b9d971a4bc39319d917c8b4f576cee67de5ca Mon Sep 17 00:00:00 2001 From: Alexander Zveruk Date: Wed, 20 May 2020 23:47:37 +0300 Subject: [PATCH 2/5] write imporant logs in status bar --- tg/controllers/__init__.py | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/tg/controllers/__init__.py b/tg/controllers/__init__.py index ba78964..4f4d011 100644 --- a/tg/controllers/__init__.py +++ b/tg/controllers/__init__.py @@ -70,6 +70,7 @@ class Controller: if file_path and os.path.isfile(file_path): chat_id = self.model.chats.id_by_index(self.model.current_chat) send_file_fun(file_path, chat_id, *args, **kwargs) + self.present_info("File sent") def send_voice(self): file_path = f"/tmp/voice-{datetime.now()}.oga" @@ -83,7 +84,7 @@ class Controller: duration = get_duration(file_path) waveform = get_waveform(file_path) self.tg.send_voice(file_path, chat_id, duration, waveform) - self.view.status.draw(f"Sent voice msg: {file_path}") + self.present_info(f"Sent voice msg: {file_path}") def run(self) -> None: try: @@ -121,15 +122,24 @@ class Controller: log.info("Opening file: %s", path) s.open_file(path) + def present_error(self, msg: str): + return self.update_status("Error", msg) + + def present_info(self, msg: str): + return self.update_status("Info", msg) + + def update_status(self, level: str, msg: str): + with self.lock: + self.view.status.draw(f"{level}: {msg}") + + def edit_msg(self): msg = MsgProxy(self.model.current_msg) log.info("Editing msg: %s", msg.msg) if not self.model.is_me(msg.sender_id): - log.warning("Can't edit other user message") - return + return self.present_error("You can edit only your messages!") if not msg.is_text: - log.warning("Can't edit not text message") - return + return self.present_error("You can edit text messages only!") with NamedTemporaryFile("r+", suffix=".txt") as f, suspend( self.view @@ -140,8 +150,7 @@ class Controller: f.seek(0) if msg := f.read().strip(): self.model.edit_message(text=msg) - with self.lock: - self.view.status.draw("Message edited") + self.present_info("Message edited") def write_long_msg(self): with NamedTemporaryFile("r+", suffix=".txt") as f, suspend( @@ -151,8 +160,7 @@ class Controller: f.seek(0) if msg := f.read().strip(): self.model.send_message(text=msg) - with self.lock: - self.view.status.draw("Message sent") + self.present_info("Message sent") def resize_handler(self, signum, frame): curses.endwin() @@ -206,8 +214,10 @@ class Controller: elif keys == "dd": if self.model.delete_msg(): self.refresh_msgs() + self.present_info("Message deleted") elif keys == "D": self.download_current_file() + self.present_info("File downloaded") elif keys == "l": self.open_current_msg() @@ -254,11 +264,11 @@ class Controller: elif keys in ("i", "a"): # write new message - msg = self.view.status.get_input() - if msg: + if msg := self.view.status.get_input(): self.model.send_message(text=msg) - with self.lock: - self.view.status.draw(f"Sent: {msg}") + self.present_info("Message sent") + else: + self.present_info("Message wasn't sent") elif keys in ("I", "A"): self.write_long_msg() From b23268b0ed44d769185767c58e66de220e4b1b59 Mon Sep 17 00:00:00 2001 From: Alexander Zveruk Date: Thu, 21 May 2020 08:00:33 +0300 Subject: [PATCH 3/5] fix styling --- tg/controllers/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tg/controllers/__init__.py b/tg/controllers/__init__.py index 4f4d011..cc26bc8 100644 --- a/tg/controllers/__init__.py +++ b/tg/controllers/__init__.py @@ -132,7 +132,6 @@ class Controller: with self.lock: self.view.status.draw(f"{level}: {msg}") - def edit_msg(self): msg = MsgProxy(self.model.current_msg) log.info("Editing msg: %s", msg.msg) From eb87e602cead18b278adfe0b8d06921d95f9172e Mon Sep 17 00:00:00 2001 From: Alexander Zveruk Date: Thu, 21 May 2020 08:40:17 +0300 Subject: [PATCH 4/5] add more status bar updates & check "can_be_edited" --- tg/controllers/__init__.py | 8 +++++++- tg/msg.py | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tg/controllers/__init__.py b/tg/controllers/__init__.py index e8ded3c..3d52202 100644 --- a/tg/controllers/__init__.py +++ b/tg/controllers/__init__.py @@ -80,7 +80,11 @@ class Controller: resp = self.view.status.get_input( f"Do you want to send recording: {file_path}? [Y/n]" ) - if is_yes(resp) and os.path.isfile(file_path): + if not is_yes(resp): + self.present_info("Voice message discarded") + elif not os.path.isfile(file_path): + self.present_info(f"Can't load recording file {file_path}") + else: chat_id = self.model.chats.id_by_index(self.model.current_chat) duration = get_duration(file_path) waveform = get_waveform(file_path) @@ -140,6 +144,8 @@ class Controller: return self.present_error("You can edit only your messages!") if not msg.is_text: return self.present_error("You can edit text messages only!") + if not msg.can_be_edited: + return self.present_error("Meessage can't be edited!") with NamedTemporaryFile("r+", suffix=".txt") as f, suspend( self.view diff --git a/tg/msg.py b/tg/msg.py index 50afa05..ba8474a 100644 --- a/tg/msg.py +++ b/tg/msg.py @@ -172,6 +172,10 @@ class MsgProxy: def msg_id(self) -> int: return self.msg["id"] + @property + def can_be_edited(self) -> bool: + return self.msg["can_be_edited"] + @property def reply_msg_id(self) -> Optional[int]: return self.msg.get("reply_to_message_id") From 2927190c761a1be180f88d04efc8a95d496a8bcb Mon Sep 17 00:00:00 2001 From: Alexander Zveruk Date: Thu, 21 May 2020 09:15:53 +0300 Subject: [PATCH 5/5] attemp to fix editing --- tg/controllers/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tg/controllers/__init__.py b/tg/controllers/__init__.py index 3d52202..84bb826 100644 --- a/tg/controllers/__init__.py +++ b/tg/controllers/__init__.py @@ -153,20 +153,20 @@ class Controller: f.write(msg.text_content) f.flush() s.call(f"{config.editor} {f.name}") - f.seek(0) - if msg := f.read().strip(): - self.model.edit_message(text=msg) - self.present_info("Message edited") + with open(f.name) as f: + if msg := f.read().strip(): + self.model.edit_message(text=msg) + self.present_info("Message edited") def write_long_msg(self): with NamedTemporaryFile("r+", suffix=".txt") as f, suspend( self.view ) as s: s.call(config.long_msg_cmd.format(file_path=f.name)) - f.seek(0) - if msg := f.read().strip(): - self.model.send_message(text=msg) - self.present_info("Message sent") + with open(f.name) as f: + if msg := f.read().strip(): + self.model.send_message(text=msg) + self.present_info("Message sent") def resize_handler(self, signum, frame): curses.endwin()