diff --git a/pyproject.toml b/pyproject.toml index f90db30..07b7a5f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,6 @@ exclude = [ ".venv", "openpgp/*", "pgp/*", - "triggers/*", ] [tool.ruff] diff --git a/triggers/gtk/config.py b/triggers/gtk/config.py index 71cfc59..d6aca64 100644 --- a/triggers/gtk/config.py +++ b/triggers/gtk/config.py @@ -17,16 +17,16 @@ from __future__ import annotations from typing import Any +from typing import cast from typing import TYPE_CHECKING from pathlib import Path -from gi.repository import Gdk from gi.repository import Gtk -from gajim.common import app from gajim.common.helpers import play_sound_file from gajim.common.util.status import get_uf_show +from gajim.gtk.widgets import GajimAppWindow from gajim.plugins.helpers import get_builder from gajim.plugins.plugins_i18n import _ @@ -40,98 +40,139 @@ EVENTS: dict[str, Any] = { RECIPIENT_TYPES = ["contact", "group", "groupchat", "all"] -class ConfigDialog(Gtk.ApplicationWindow): +class ConfigBuilder(Gtk.Builder): + liststore1: Gtk.ListStore + liststore2: Gtk.ListStore + box: Gtk.Box + rules_box: Gtk.Box + conditions_treeview: Gtk.TreeView + up_button: Gtk.Button + down_button: Gtk.Button + new_button: Gtk.Button + delete_button: Gtk.Button + config_box: Gtk.Box + event_combobox: Gtk.ComboBox + recipient_type_combobox: Gtk.ComboBox + recipient_list_entry: Gtk.Entry + all_status_rb: Gtk.CheckButton + special_status_rb: Gtk.CheckButton + status_expander: Gtk.Expander + online_cb: Gtk.CheckButton + away_cb: Gtk.CheckButton + xa_cb: Gtk.CheckButton + dnd_cb: Gtk.CheckButton + tab_opened_cb: Gtk.CheckButton + has_focus_cb: Gtk.CheckButton + not_tab_opened_cb: Gtk.CheckButton + not_has_focus_cb: Gtk.CheckButton + use_popup_cb: Gtk.CheckButton + disable_popup_cb: Gtk.CheckButton + use_sound_cb: Gtk.CheckButton + sound_file_box: Gtk.Box + play_button: Gtk.Button + disable_sound_cb: Gtk.CheckButton + run_command_cb: Gtk.CheckButton + command_entry: Gtk.Entry + one_shot_cb: Gtk.CheckButton + + +class ConfigDialog(GajimAppWindow): def __init__(self, plugin: Triggers, transient: Gtk.Window) -> None: - Gtk.ApplicationWindow.__init__(self) - self.set_application(app.app) - self.set_show_menubar(False) - self.set_title(_("Triggers Configuration")) - self.set_transient_for(transient) - self.set_default_size(600, 800) - self.set_type_hint(Gdk.WindowTypeHint.DIALOG) - self.set_modal(True) - self.set_destroy_with_parent(True) + + GajimAppWindow.__init__( + self, + name="TriggersConfigDialog", + title=_("Triggers Configuration"), + default_width=600, + default_height=800, + transient_for=transient, + modal=True, + ) ui_path = Path(__file__).parent - self._ui = get_builder(str(ui_path.resolve() / "config.ui")) + self._ui = cast( + ConfigBuilder, get_builder(str(ui_path.resolve() / "config.ui")) + ) self._plugin = plugin - self.add(self._ui.box) - self.show_all() + self.set_child(self._ui.box) self._active_num = -1 self._config: dict[int, Any] = {} self._initialize() - self._ui.connect_signals(self) - self.connect("destroy", self._on_destroy) + self._connect( + self._ui.conditions_treeview, + "cursor-changed", + self._on_conditions_treeview_cursor_changed, + ) + self._connect(self._ui.up_button, "clicked", self._on_up_button_clicked) + self._connect(self._ui.down_button, "clicked", self._on_down_button_clicked) + self._connect(self._ui.new_button, "clicked", self._on_new_button_clicked) + self._connect(self._ui.delete_button, "clicked", self._on_delete_button_clicked) + self._connect( + self._ui.event_combobox, "changed", self._on_event_combobox_changed + ) + self._connect( + self._ui.recipient_type_combobox, + "changed", + self._on_recipient_type_combobox_changed, + ) + self._connect( + self._ui.recipient_list_entry, + "changed", + self._on_recipient_list_entry_changed, + ) + self._connect( + self._ui.all_status_rb, "toggled", self._on_status_radiobutton_toggled + ) + self._connect(self._ui.online_cb, "toggled", self._on_status_cb_toggled) + self._connect(self._ui.away_cb, "toggled", self._on_status_cb_toggled) + self._connect(self._ui.xa_cb, "toggled", self._on_status_cb_toggled) + self._connect(self._ui.dnd_cb, "toggled", self._on_status_cb_toggled) + self._connect(self._ui.tab_opened_cb, "toggled", self._on_tab_opened_cb_toggled) + self._connect(self._ui.has_focus_cb, "toggled", self._on_has_focus_cb_toggled) + self._connect( + self._ui.not_tab_opened_cb, "toggled", self._on_not_tab_opened_cb_toggled + ) + self._connect( + self._ui.not_has_focus_cb, "toggled", self._on_not_has_focus_cb_toggled + ) + self._connect(self._ui.use_popup_cb, "toggled", self._on_use_popup_cb_toggled) + self._connect( + self._ui.disable_popup_cb, "toggled", self._on_disable_popup_cb_toggled + ) + self._connect(self._ui.use_sound_cb, "toggled", self._on_use_sound_cb_toggled) + self._connect(self._ui.play_button, "clicked", self._on_play_button_clicked) + self._connect( + self._ui.disable_sound_cb, "toggled", self._on_disable_sound_cb_toggled + ) + self._connect( + self._ui.run_command_cb, "toggled", self._on_run_command_cb_toggled + ) + self._connect(self._ui.command_entry, "changed", self._on_command_entry_changed) + self._connect(self._ui.one_shot_cb, "toggled", self._on_one_shot_cb_toggled) + self._connect(self.window, "close-request", self._on_close_request) - def _on_destroy(self, *args: Any) -> None: + self.show() + + def _cleanup(self) -> None: + pass + + def _on_close_request(self, *args: Any) -> None: for num in list(self._plugin.config.keys()): del self._plugin.config[num] for num in self._config: self._plugin.config[str(num)] = self._config[num] def _initialize(self) -> None: - # Fill window - widgets = [ - "conditions_treeview", - "config_box", - "event_combobox", - "recipient_type_combobox", - "recipient_list_entry", - "delete_button", - "online_cb", - "away_cb", - "xa_cb", - "dnd_cb", - "use_sound_cb", - "disable_sound_cb", - "use_popup_cb", - "disable_popup_cb", - "tab_opened_cb", - "not_tab_opened_cb", - "has_focus_cb", - "not_has_focus_cb", - "filechooser", - "sound_file_box", - "up_button", - "down_button", - "run_command_cb", - "command_entry", - "one_shot_cb", - ] - for widget in widgets: - self._ui.__dict__[widget] = self._ui.get_object(widget) - self._config = {} - for num in self._plugin.config.keys(): + for num in self._plugin.config: self._config[int(num)] = self._plugin.config[num] - if not self._ui.conditions_treeview.get_column(0): - # Window never opened - model = Gtk.ListStore(int, str) - model.set_sort_column_id(0, Gtk.SortType.ASCENDING) - self._ui.conditions_treeview.set_model(model) - - # '#' Means number - col = Gtk.TreeViewColumn(_("#")) - self._ui.conditions_treeview.append_column(col) - renderer = Gtk.CellRendererText() - col.pack_start(renderer, expand=False) - col.add_attribute(renderer, "text", 0) - - col = Gtk.TreeViewColumn(_("Condition")) - self._ui.conditions_treeview.append_column(col) - renderer = Gtk.CellRendererText() - col.pack_start(renderer, expand=True) - col.add_attribute(renderer, "text", 1) - else: - model = self._ui.conditions_treeview.get_model() - - model.clear() + model = cast(Gtk.ListStore, self._ui.conditions_treeview.get_model()) # Fill conditions_treeview num = 0 @@ -152,16 +193,16 @@ class ConfigDialog(Gtk.ApplicationWindow): self._ui.down_button.set_sensitive(False) self._ui.up_button.set_sensitive(False) - filter_ = Gtk.FileFilter() - filter_.set_name(_("All Files")) - filter_.add_pattern("*") - self._ui.filechooser.add_filter(filter_) + # filter_ = Gtk.FileFilter() + # filter_.set_name(_("All Files")) + # filter_.add_pattern("*") + # self._ui.filechooser.add_filter(filter_) - filter_ = Gtk.FileFilter() - filter_.set_name(_("Wav Sounds")) - filter_.add_pattern("*.wav") - self._ui.filechooser.add_filter(filter_) - self._ui.filechooser.set_filter(filter_) + # filter_ = Gtk.FileFilter() + # filter_.set_name(_("Wav Sounds")) + # filter_.add_pattern("*.wav") + # self._ui.filechooser.add_filter(filter_) + # self._ui.filechooser.set_filter(filter_) def _initiate_rule_state(self) -> None: """ @@ -202,11 +243,11 @@ class ConfigDialog(Gtk.ApplicationWindow): else: self._ui.special_status_rb.set_active(True) values = value.split() - for val in ("online", "away", "xa", "dnd"): - if val in values: - self._ui.__dict__[val + "_cb"].set_active(True) + for st in ("online", "away", "xa", "dnd"): + if st in values: + getattr(self._ui, f"{st}_cb").set_active(True) else: - self._ui.__dict__[val + "_cb"].set_active(False) + getattr(self._ui, f"{st}_cb").set_active(False) self._on_status_radiobutton_toggled(self._ui.all_status_rb) @@ -230,24 +271,25 @@ class ConfigDialog(Gtk.ApplicationWindow): elif value == "yes": self._ui.not_has_focus_cb.set_active(False) + # TODO # sound_file - value = self._config[self._active_num]["sound_file"] - if value is None: - self._ui.filechooser.unselect_all() - else: - self._ui.filechooser.set_filename(value) + # value = self._config[self._active_num]["sound_file"] + # if value is None: + # self._ui.filechooser.unselect_all() + # else: + # self._ui.filechooser.set_filename(value) # sound, popup, auto_open, systray, roster for option in ("sound", "popup"): value = self._config[self._active_num][option] if value == "yes": - self._ui.__dict__["use_" + option + "_cb"].set_active(True) + getattr(self._ui, f"use_{option}_cb").set_active(True) else: - self._ui.__dict__["use_" + option + "_cb"].set_active(False) + getattr(self._ui, f"use_{option}_cb").set_active(False) if value == "no": - self._ui.__dict__["disable_" + option + "_cb"].set_active(True) + getattr(self._ui, f"disable_{option}_cb").set_active(True) else: - self._ui.__dict__["disable_" + option + "_cb"].set_active(False) + getattr(self._ui, f"disable_{option}_cb").set_active(False) # run_command value = self._config[self._active_num]["run_command"] @@ -258,10 +300,7 @@ class ConfigDialog(Gtk.ApplicationWindow): self._ui.command_entry.set_text(value) # one shot - if "one_shot" in self._config[self._active_num]: - value = self._config[self._active_num]["one_shot"] - else: - value = False + value = self._config[self._active_num].get("one_shot", False) self._ui.one_shot_cb.set_active(value) def _set_treeview_string(self) -> None: @@ -269,15 +308,21 @@ class ConfigDialog(Gtk.ApplicationWindow): (model, iter_) = selection.get_selected() if not iter_: return - ind = self._ui.event_combobox.get_active() + event = "" + ind = self._ui.event_combobox.get_active() if ind > -1: - event = self._ui.event_combobox.get_model()[ind][0] + event_model = self._ui.event_combobox.get_model() + assert event_model is not None + event = event_model[ind][0] + ind = self._ui.recipient_type_combobox.get_active() recipient_type = "" if ind > -1: recipient_type_model = self._ui.recipient_type_combobox.get_model() + assert recipient_type_model is not None recipient_type = recipient_type_model[ind][0] + recipient = "" if recipient_type != "everybody": recipient = self._ui.recipient_list_entry.get_text() @@ -286,8 +331,9 @@ class ConfigDialog(Gtk.ApplicationWindow): else: status = _("and I am ") for st in ("online", "away", "xa", "dnd"): - if self._ui.__dict__[st + "_cb"].get_active(): + if getattr(self._ui, f"{st}_cb").get_active(): status += get_uf_show(st) + " " + model[iter_][1] = _( "%(event)s (%(recipient_type)s) %(recipient)s %(status)s" ) % { @@ -298,7 +344,6 @@ class ConfigDialog(Gtk.ApplicationWindow): } def _on_conditions_treeview_cursor_changed(self, widget: Gtk.TreeView) -> None: - (model, iter_) = widget.get_selection().get_selected() if not iter_: self._active_num = -1 @@ -320,8 +365,9 @@ class ConfigDialog(Gtk.ApplicationWindow): self._ui.delete_button.set_sensitive(True) def _on_new_button_clicked(self, _button: Gtk.Button) -> None: - model = self._ui.conditions_treeview.get_model() - num = self._ui.conditions_treeview.get_model().iter_n_children(None) + model = cast(Gtk.ListStore, self._ui.conditions_treeview.get_model()) + assert model is not None + num = model.iter_n_children(None) self._config[num] = { "event": "message_received", "recipient_type": "all", @@ -336,6 +382,7 @@ class ConfigDialog(Gtk.ApplicationWindow): "command": "", "one_shot": False, } + iter_ = model.append((num, "")) path = model.get_path(iter_) self._ui.conditions_treeview.set_cursor(path) @@ -346,8 +393,10 @@ class ConfigDialog(Gtk.ApplicationWindow): def _on_delete_button_clicked(self, button: Gtk.Button) -> None: selection = self._ui.conditions_treeview.get_selection() (model, iter_) = selection.get_selected() + assert isinstance(model, Gtk.ListStore) if not iter_: return + # up all others iter2 = model.iter_next(iter_) num = self._active_num @@ -356,6 +405,7 @@ class ConfigDialog(Gtk.ApplicationWindow): model[iter2][0] = num - 1 self._config[num - 1] = self._config[num].copy() iter2 = model.iter_next(iter2) + model.remove(iter_) del self._config[num] self._active_num = -1 @@ -367,8 +417,10 @@ class ConfigDialog(Gtk.ApplicationWindow): def _on_up_button_clicked(self, _button: Gtk.Button) -> None: selection = self._ui.conditions_treeview.get_selection() (model, iter_) = selection.get_selected() + assert isinstance(model, Gtk.ListStore) if not iter_: return + conf = self._config[self._active_num].copy() self._config[self._active_num] = self._config[self._active_num - 1] self._config[self._active_num - 1] = conf @@ -383,14 +435,17 @@ class ConfigDialog(Gtk.ApplicationWindow): def _on_down_button_clicked(self, _button: Gtk.Button) -> None: selection = self._ui.conditions_treeview.get_selection() (model, iter_) = selection.get_selected() + assert isinstance(model, Gtk.ListStore) if not iter_: return + conf = self._config[self._active_num].copy() self._config[self._active_num] = self._config[self._active_num + 1] self._config[self._active_num + 1] = conf model[iter_][0] = self._active_num + 1 iter_ = model.iter_next(iter_) + assert iter_ is not None model[iter_][0] = self._active_num self._on_conditions_treeview_cursor_changed(self._ui.conditions_treeview) @@ -432,14 +487,14 @@ class ConfigDialog(Gtk.ApplicationWindow): return status = "" for st in ("online", "away", "xa", "dnd"): - if self._ui.__dict__[st + "_cb"].get_active(): + if getattr(self._ui, f"{st}_cb").get_active(): status += st + " " if status: status = status[:-1] self._config[self._active_num]["status"] = status self._set_treeview_string() - def _on_status_radiobutton_toggled(self, _widget: Gtk.RadioButton) -> None: + def _on_status_radiobutton_toggled(self, _widget: Gtk.CheckButton) -> None: if self._active_num < 0: return if self._ui.all_status_rb.get_active(): @@ -447,13 +502,13 @@ class ConfigDialog(Gtk.ApplicationWindow): self._config[self._active_num]["status"] = "all" # 'All status' clicked for st in ("online", "away", "xa", "dnd"): - self._ui.__dict__[st + "_cb"].set_sensitive(False) + getattr(self._ui, f"{st}_cb").set_sensitive(False) else: self._ui.status_expander.set_expanded(True) self._set_status_config() # 'special status' clicked for st in ("online", "away", "xa", "dnd"): - self._ui.__dict__[st + "_cb"].set_sensitive(True) + getattr(self._ui, f"{st}_cb").set_sensitive(True) self._set_treeview_string() diff --git a/triggers/gtk/config.ui b/triggers/gtk/config.ui index 8d1ed39..46acf2b 100644 --- a/triggers/gtk/config.ui +++ b/triggers/gtk/config.ui @@ -1,10 +1,14 @@ - - + + + + + + + - @@ -24,7 +28,6 @@ - @@ -34,879 +37,556 @@ - True - False - 18 vertical 6 - True - True - True - True - + 1 + 1 + 1 + 1 + 1 + - True - False - + - True - False vertical 6 - True - False vertical 100 - True - True - in - + 1 + - True - True + 1 + conditions_store horizontal - + + + 1 + # + 1 + 1 + 0 + + + 0 + + + 0 + + + + + + + 1 + Condition + 1 + 1 + 1 + + + 0 + + + 1 + + + + - + - - False - True - 0 - - - True - False - False - 1 - - - True - False - False - Up - Up - True - go-up-symbolic - - - - False - True - - - - - True - False - False - Down - Down - True - go-down-symbolic - - - - False - True - - - - - True - False - New rule - New rule - True - list-add-symbolic - - - - False - True - - - - - True - False - Delete rule - Delete rule - True - list-remove-symbolic - - - - False - True - - + + toolbar + + + 0 + Up + Up + 1 + go-up-symbolic + + + + + 0 + Down + Down + 1 + go-down-symbolic + + + + + New rule + New rule + 1 + list-add-symbolic + + + + + Delete rule + Delete rule + 1 + list-remove-symbolic + + - - False - True - 1 - - - False - True - 0 - - True - False + 1 vertical 5 - True - False center vertical 6 - True - False + center 6 - Conditions - True + Conditions + 1 - - False - False - 0 - - - True - False center 6 12 - True - False end - Event - True + Event + 1 + + 0 + 0 + - - 0 - 0 - 200 - True - False liststore2 - 0 + + 1 + 0 + - - 1 - 0 - - True - False end - Category - True + Category + 1 + + 0 + 1 + - - 0 - 1 - - True - False liststore1 - 0 + + 1 + 1 + - - 1 - 1 - 300 - True - False - True - comma separated list - + 0 + 1 + comma separated list + + 1 + 2 + - - 1 - 2 - - True - False end - List + List + + 0 + 2 + - - 0 - 2 - - - False - True - 1 - - True - False center 6 6 - True - False start - My status - True + My status + 1 - - False - True - 0 - - - All statuses - True - True - False + + All statuses + 1 start - True - True - special_status_rb - + 1 - - False - True - 1 - - - Certain status - True - True - False + + Certain status + 1 start - True - True + 1 all_status_rb - - False - True - 2 - - True - True + 1 start 3 - True + 1 - True - False vertical 6 - Online - True - False - True - False + Online + 0 + 1 start - True - True - + 1 - - False - True - 0 - - Away - True - False - True - False + Away + 0 + 1 start - True - True - + 1 - - False - True - 1 - - Not Available - True - False - True - False + Not Available + 0 + 1 start - True - True - + 1 - - False - True - 2 - - Busy - True - False - True - False + Busy + 0 + 1 start - True - True - + 1 - - False - True - 3 - - True - False - Status + Status - - False - True - 3 - - - False - True - 2 - - - True - False 6 12 - True - False end - Chat Window + Chat Window + + 0 + 0 + - - 0 - 0 - - True - False end - Focus + Focus + + 0 + 1 + - - 0 - 1 - - Opened - True - True - False + Opened + 1 start - True - True - + 1 + + 1 + 0 + - - 1 - 0 - - Has focus - True - True - False + Has focus + 1 start - True - + + 1 + 1 + - - 1 - 1 - - Not opened - True - True - False + Not opened + 1 start - True - True - + 1 + + 2 + 0 + - - 2 - 0 - - Does not have focus - True - True - False + Does not have focus + 1 start - True - + + 2 + 1 + - - 2 - 1 - - - False - True - 5 - - - False - True - 0 - - True - False center vertical 6 - True - False + center 6 - Actions - True + Actions + 1 - - False - False - 0 - - True - False vertical 6 - True - False start - Notifications + Notifications - - False - True - 0 - - Not_ify me with a popup - True - True - False + Not_ify me with a popup + 1 start - True - True - + 1 - - False - True - 1 - - _Disable existing notification - True - True - False + _Disable existing notification + 1 start - True - True - + 1 - - False - True - 2 - - - False - True - 1 - - True - False vertical 6 - True - False start - Sounds - True + Sounds + 1 - - False - True - 0 - - True - False + center start 12 - Play sound - True - True - False + Play sound + 1 start - True - True - + 1 - - False - True - 0 - - True - False 12 - + - True - True - False - + 1 - True - False media-playback-start-symbolic - - False - True - 1 - - - False - True - 1 - - - False - False - 1 - - _Disable existing sound for this event - True - True - False + _Disable existing sound for this event + 1 start - True - True - + 1 - - False - True - 2 - - - False - True - 2 - - True - False start - Advanced + Advanced - - False - True - 3 - - True - False + center 6 - Launch command - True - True - False - True - True - + Launch command + 1 + 1 - - False - True - 0 - 200 - True - True - Command... - + 1 + Command... - - False - True - 1 - - - False - False - 4 - - Delete this rule once applied - True - True - False + Delete this rule once applied + 1 start - True - - - False - True - 5 - - - False - True - 1 - - - True - True - 1 - - + - + - - True - True - 2 - diff --git a/triggers/triggers.py b/triggers/triggers.py index 4735cef..196459f 100644 --- a/triggers/triggers.py +++ b/triggers/triggers.py @@ -18,12 +18,11 @@ from __future__ import annotations from typing import Any -from typing import Callable from typing import cast -from typing import Union import logging import subprocess +from collections.abc import Callable from functools import partial from nbxmpp.protocol import JID @@ -36,6 +35,7 @@ from gajim.common.events import MessageReceived from gajim.common.events import Notification from gajim.common.events import PresenceReceived from gajim.common.helpers import play_sound_file +from gajim.common.modules.contacts import BareContact from gajim.plugins import GajimPlugin from gajim.plugins.plugins_i18n import _ @@ -45,7 +45,7 @@ from triggers.util import RuleResult log = logging.getLogger("gajim.p.triggers") -ProcessableEventsT = Union[MessageReceived, Notification, PresenceReceived] +ProcessableEventsT = MessageReceived | Notification | PresenceReceived RuleT = dict[str, Any] @@ -106,14 +106,14 @@ class Triggers(GajimPlugin): result = RuleResult() - rules_num = [int(item) for item in self.config.keys()] + rules_num = [int(item) for item in self.config] rules_num.sort() to_remove: list[int] = [] for num in rules_num: rule = cast(RuleT, self.config[str(num)]) if check_func(event, rule): apply_func(result, rule) - if "one_shot" in rule and rule["one_shot"]: + if rule.get("one_shot"): to_remove.append(num) decal = 0 @@ -136,31 +136,26 @@ class Triggers(GajimPlugin): def _check_rule_apply_msg_received( self, event: MessageReceived, rule: RuleT ) -> bool: - return self._check_rule_all("message_received", event, rule) @log_result def _check_rule_apply_connected(self, event: PresenceReceived, rule: RuleT) -> bool: - return self._check_rule_all("contact_connected", event, rule) @log_result def _check_rule_apply_disconnected( self, event: PresenceReceived, rule: RuleT ) -> bool: - return self._check_rule_all("contact_disconnected", event, rule) @log_result def _check_rule_apply_status_changed( self, event: PresenceReceived, rule: RuleT ) -> bool: - return self._check_rule_all("contact_status_change", event, rule) @log_result def _check_rule_apply_notification(self, event: Notification, rule: RuleT) -> bool: - # Check notification type notif_type = "" if event.type == "incoming-message": @@ -181,7 +176,6 @@ class Triggers(GajimPlugin): def _check_rule_all( self, notif_type: str, event: ProcessableEventsT, rule: RuleT ) -> bool: - # Check notification type if rule["event"] != notif_type: return False @@ -207,7 +201,7 @@ class Triggers(GajimPlugin): @log_result def _check_rule_recipients(self, event: ProcessableEventsT, rule: RuleT) -> bool: - + assert event.jid is not None rule_recipients = [t.strip() for t in rule["recipients"].split(",")] if rule["recipient_type"] == "groupchat": if event.jid in rule_recipients: @@ -218,7 +212,11 @@ class Triggers(GajimPlugin): client = app.get_client(event.account) contact = client.get_module("Contacts").get_contact(event.jid) - if contact.is_groupchat or not contact.is_in_roster: + if contact.is_groupchat: + return False + + assert isinstance(contact, BareContact) + if not contact.is_in_roster: return False group_found = False @@ -233,7 +231,6 @@ class Triggers(GajimPlugin): @log_result def _check_rule_status(self, event: ProcessableEventsT, rule: RuleT) -> bool: - rule_statuses = rule["status"].split() client = app.get_client(event.account) if rule["status"] != "all" and client.status not in rule_statuses: @@ -243,7 +240,6 @@ class Triggers(GajimPlugin): @log_result def _check_rule_tab_opened(self, event: ProcessableEventsT, rule: RuleT) -> bool: - if rule["tab_opened"] == "both": return True tab_opened = False @@ -259,7 +255,6 @@ class Triggers(GajimPlugin): @log_result def _check_rule_has_focus(self, event: ProcessableEventsT, rule: RuleT) -> bool: - if rule["has_focus"] == "both": return True if rule["tab_opened"] == "no": @@ -311,7 +306,7 @@ class Triggers(GajimPlugin): if result.command is not None: try: - subprocess.Popen(f"{result.command} &", shell=True).wait() + subprocess.Popen(f"{result.command} &", shell=True).wait() # noqa: S602 except Exception: pass diff --git a/triggers/util.py b/triggers/util.py index a3acb21..ae6ae2d 100644 --- a/triggers/util.py +++ b/triggers/util.py @@ -15,10 +15,10 @@ from __future__ import annotations from typing import Any -from typing import Callable from typing import TYPE_CHECKING import logging +from collections.abc import Callable from dataclasses import dataclass if TYPE_CHECKING: @@ -31,7 +31,7 @@ log = logging.getLogger("gajim.p.triggers") def log_result(func: Callable[..., Any]) -> Callable[..., bool]: def wrapper(self: Any, event: ProcessableEventsT, rule: RuleT): res = func(self, event, rule) - log.info(f"{event.name} -> {func.__name__} -> {res}") + log.info("%s -> %s -> %s", event.name, func.__name__, res) return res return wrapper