diff --git a/toxygen/contacts/contact_menu.py b/toxygen/contacts/contact_menu.py index 63d0d36..7330b35 100644 --- a/toxygen/contacts/contact_menu.py +++ b/toxygen/contacts/contact_menu.py @@ -187,6 +187,9 @@ class GroupMenuGenerator(BaseContactMenuGenerator): .with_optional_action(util_ui.tr('Set topic'), lambda: groups_service.set_group_topic(self._contact), self._contact.is_self_moderator_or_founder()) + .with_optional_action(util_ui.tr('Bans list'), + lambda: groups_service.show_bans_list(self._contact), + self._contact.is_self_moderator_or_founder()) .with_action(util_ui.tr('Reconnect to group'), lambda: groups_service.reconnect_to_group(self._contact.number)) .with_optional_action(util_ui.tr('Disconnect from group'), diff --git a/toxygen/contacts/group_chat.py b/toxygen/contacts/group_chat.py index e89b561..f173695 100644 --- a/toxygen/contacts/group_chat.py +++ b/toxygen/contacts/group_chat.py @@ -4,6 +4,7 @@ import utils.util as util from groups.group_peer import GroupChatPeer from wrapper import toxcore_enums_and_consts as constants from common.tox_save import ToxSave +from groups.group_ban import GroupBan class GroupChat(contact.Contact, ToxSave): @@ -102,6 +103,19 @@ class GroupChat(contact.Contact, ToxSave): peers = property(get_peers) + def get_bans(self): + ban_ids = self._tox.group_ban_get_list(self._number) + bans = [] + for ban_id in ban_ids: + ban = GroupBan(ban_id, + self._tox.group_ban_get_target(self._number, ban_id), + self._tox.group_ban_get_time_set(self._number, ban_id)) + bans.append(ban) + + return bans + + bans = property(get_bans) + # ----------------------------------------------------------------------------------------------------------------- # Private methods # ----------------------------------------------------------------------------------------------------------------- diff --git a/toxygen/groups/group_ban.py b/toxygen/groups/group_ban.py new file mode 100644 index 0000000..89ecc7e --- /dev/null +++ b/toxygen/groups/group_ban.py @@ -0,0 +1,23 @@ + + +class GroupBan: + + def __init__(self, ban_id, ban_target, ban_time): + self._ban_id = ban_id + self._ban_target = ban_target + self._ban_time = ban_time + + def get_ban_id(self): + return self._ban_id + + ban_id = property(get_ban_id) + + def get_ban_target(self): + return self._ban_target + + ban_target = property(get_ban_target) + + def get_ban_time(self): + return self._ban_time + + ban_time = property(get_ban_time) diff --git a/toxygen/groups/groups_service.py b/toxygen/groups/groups_service.py index 4cf1368..19b53cf 100644 --- a/toxygen/groups/groups_service.py +++ b/toxygen/groups/groups_service.py @@ -15,7 +15,7 @@ class GroupsService(tox_save.ToxSave): self._peers_list_widget = main_screen.peers_list self._widgets_factory_provider = widgets_factory_provider self._group_invites = [] - self._peer_screen = self._management_screen = None + self._screen = None def set_tox(self, tox): super().set_tox(tox) @@ -114,8 +114,8 @@ class GroupsService(tox_save.ToxSave): def show_group_management_screen(self, group): widgets_factory = self._get_widgets_factory() - self._management_screen = widgets_factory.create_group_management_screen(group) - self._management_screen.show() + self._screen = widgets_factory.create_group_management_screen(group) + self._screen.show() def set_group_password(self, group, password): if group.password == password: @@ -151,10 +151,10 @@ class GroupsService(tox_save.ToxSave): group = self._get_group_by_public_key(chat_id) self_peer = group.get_self_peer() if self_peer.id != peer_id: - self._peer_screen = widgets_factory.create_peer_screen_window(group, peer_id) + self._screen = widgets_factory.create_peer_screen_window(group, peer_id) else: - self._peer_screen = widgets_factory.create_self_peer_screen_window(group) - self._peer_screen.show() + self._screen = widgets_factory.create_self_peer_screen_window(group) + self._screen.show() # ----------------------------------------------------------------------------------------------------------------- # Peers actions @@ -177,6 +177,26 @@ class GroupsService(tox_save.ToxSave): self_peer.status = status self.generate_peers_list() + # ----------------------------------------------------------------------------------------------------------------- + # Bans support + # ----------------------------------------------------------------------------------------------------------------- + + def show_bans_list(self, group): + widgets_factory = self._get_widgets_factory() + self._screen = widgets_factory.create_groups_bans_screen(group) + self._screen.show() + + def ban_peer(self, group, peer_id, ban_type): + self._tox.group_mod_ban_peer(group.number, peer_id, ban_type) + group.remove_peer(peer_id) + + def kick_peer(self, group, peer_id): + self._tox.group_mod_remove_peer(group.number, peer_id) + group.remove_peer(peer_id) + + def cancel_ban(self, group_number, ban_id): + self._tox.group_mod_remove_ban(group_number, ban_id) + # ----------------------------------------------------------------------------------------------------------------- # Private methods # ----------------------------------------------------------------------------------------------------------------- diff --git a/toxygen/ui/group_bans_widgets.py b/toxygen/ui/group_bans_widgets.py new file mode 100644 index 0000000..45a5f2b --- /dev/null +++ b/toxygen/ui/group_bans_widgets.py @@ -0,0 +1,62 @@ +from ui.widgets import CenteredWidget +from PyQt5 import uic, QtWidgets, QtCore +import utils.util as util +import utils.ui as util_ui + + +class GroupBanItem(QtWidgets.QWidget): + + def __init__(self, ban, cancel_ban, parent=None): + super().__init__(parent) + self._ban = ban + self._cancel_ban = cancel_ban + + def _update_ui(self): + self._retranslate_ui() + + self.banTargetLabel.setText(self._ban.target) + ban_time = self._ban.ban_time + self.banTimeLabel.setText(util.unix_time_to_long_str(ban_time)) + + self.cancelPushButton.clicked.connect(self._cancel_ban) + + def _retranslate_ui(self): + self.cancelPushButton.setText(util_ui.tr('Cancel ban')) + + def _cancel_ban(self): + self._cancel_ban(self._ban.ban_id) + + +class GroupBansScreen(CenteredWidget): + + def __init__(self, groups_service, group): + super().__init__() + self._groups_service = groups_service + self._group = group + + uic.loadUi(util.get_views_path('bans_list_screen'), self) + self._update_ui() + + def _update_ui(self): + self._retranslate_ui() + + self._refresh_bans_list() + + def _retranslate_ui(self): + self.setWindowTitle(util_ui.tr('Bans list for group "{}"').format(self._group.name)) + + def _refresh_bans_list(self): + self.bansListWidget.clear() + for ban in self._group.bans: + self._create_ban_item(ban) + + def _create_ban_item(self, ban): + item = GroupBanItem(ban, self._on_ban_cancelled, self.bansListWidget) + elem = QtWidgets.QListWidgetItem() + elem.setSizeHint(QtCore.QSize(item.width(), item.height())) + self.bansListWidget.addItem(elem) + self.bansListWidget.setItemWidget(elem, item) + + def _on_ban_cancelled(self, ban_id): + self._groups_service.cancel_ban(self._group.number, ban_id) + self._refresh_bans_list() diff --git a/toxygen/ui/peer_screen.py b/toxygen/ui/peer_screen.py index 651d998..687c818 100644 --- a/toxygen/ui/peer_screen.py +++ b/toxygen/ui/peer_screen.py @@ -1,8 +1,9 @@ from ui.widgets import CenteredWidget -from PyQt5 import QtCore, QtWidgets, uic +from PyQt5 import uic import utils.util as util import utils.ui as util_ui from ui.contact_items import * +import wrapper.toxcore_enums_and_consts as consts class PeerScreen(CenteredWidget): @@ -35,9 +36,12 @@ class PeerScreen(CenteredWidget): self.sendPrivateMessagePushButton.clicked.connect(self._send_private_message) self.copyPublicKeyPushButton.clicked.connect(self._copy_public_key) self.roleNameLabel.setText(self._get_role_name()) - can_change_role = self._can_change_role() - self.rolesComboBox.setVisible(can_change_role) - self.roleNameLabel.setVisible(not can_change_role) + can_change_role_or_ban = self._can_change_role_or_ban() + self.rolesComboBox.setVisible(can_change_role_or_ban) + self.roleNameLabel.setVisible(not can_change_role_or_ban) + self.banGroupBox.setEnabled(can_change_role_or_ban) + self.banPushButton.clicked.connect(self._ban_peer) + self.kickPushButton.clicked.connect(self._kick_peer) self._retranslate_ui() @@ -49,7 +53,12 @@ class PeerScreen(CenteredWidget): self.roleLabel.setText(util_ui.tr('Role:')) self.copyPublicKeyPushButton.setText(util_ui.tr('Copy public key')) self.sendPrivateMessagePushButton.setText(util_ui.tr('Send private message')) - self.banGroupBox.setTitle(util_ui.tr('Moderation')) + self.banPushButton.setText(util_ui.tr('Ban peer')) + self.kickPushButton.setText(util_ui.tr('Kick peer')) + self.banGroupBox.setTitle(util_ui.tr('Ban peer')) + self.ipBanRadioButton.setText(util_ui.tr('IP')) + self.nickBanRadioButton.setText(util_ui.tr('Nickname')) + self.pkBanRadioButton.setText(util_ui.tr('Public key')) self.rolesComboBox.clear() index = self._group.get_self_peer().role @@ -58,7 +67,7 @@ class PeerScreen(CenteredWidget): self.rolesComboBox.addItem(role) self.rolesComboBox.setCurrentIndex(self._peer.role - index - 1) - def _can_change_role(self): + def _can_change_role_or_ban(self): self_peer = self._group.get_self_peer() if self_peer.role > TOX_GROUP_ROLE['MODERATOR']: return False @@ -85,3 +94,17 @@ class PeerScreen(CenteredWidget): def _copy_public_key(self): clipboard = QtWidgets.QApplication.clipboard() clipboard.setText(self._peer.public_key) + + def _ban_peer(self): + ban_type = self._get_ban_type() + self._groups_service.ban_peer(self._group, self._peer.id, ban_type) + + def _kick_peer(self): + self._groups_service.kick_peer(self._group, self._peer.id) + + def _get_ban_type(self): + if self.ipBanRadioButton.isChecked(): + return consts.TOX_GROUP_BAN_TYPE['IP_PORT'] + elif self.nickRadioButton.isCHecked(): + return consts.TOX_GROUP_BAN_TYPE['NICK'] + return consts.TOX_GROUP_BAN_TYPE['PUBLIC_KEY'] diff --git a/toxygen/ui/views/bans_list_screen.ui b/toxygen/ui/views/bans_list_screen.ui new file mode 100644 index 0000000..16339d8 --- /dev/null +++ b/toxygen/ui/views/bans_list_screen.ui @@ -0,0 +1,29 @@ + + + Form + + + + 0 + 0 + 500 + 375 + + + + Form + + + + + 0 + 0 + 500 + 375 + + + + + + + diff --git a/toxygen/ui/views/gc_ban_item.ui b/toxygen/ui/views/gc_ban_item.ui new file mode 100644 index 0000000..20e1e16 --- /dev/null +++ b/toxygen/ui/views/gc_ban_item.ui @@ -0,0 +1,58 @@ + + + Form + + + + 0 + 0 + 500 + 100 + + + + Form + + + + + 320 + 30 + 161 + 41 + + + + PushButton + + + + + + 20 + 20 + 200 + 20 + + + + TextLabel + + + + + + 20 + 50 + 200 + 20 + + + + TextLabel + + + + + + diff --git a/toxygen/ui/views/peer_screen.ui b/toxygen/ui/views/peer_screen.ui index f6b13b3..a66ec11 100644 --- a/toxygen/ui/views/peer_screen.ui +++ b/toxygen/ui/views/peer_screen.ui @@ -76,6 +76,74 @@ GroupBox + + + + 380 + 50 + 101 + 41 + + + + PushButton + + + + + + 40 + 40 + 251 + 23 + + + + RadioButton + + + true + + + + + + 40 + 80 + 251 + 23 + + + + RadioButton + + + + + + 40 + 120 + 251 + 23 + + + + RadioButton + + + + + + 380 + 100 + 101 + 41 + + + + PushButton + + diff --git a/toxygen/ui/widgets_factory.py b/toxygen/ui/widgets_factory.py index e394684..b146088 100644 --- a/toxygen/ui/widgets_factory.py +++ b/toxygen/ui/widgets_factory.py @@ -5,6 +5,7 @@ from ui.peer_screen import * from ui.self_peer_screen import * from ui.group_invites_widgets import * from ui.group_management_screen import * +from ui.group_bans_widgets import * class WidgetsFactory: @@ -86,3 +87,6 @@ class WidgetsFactory: def create_group_management_screen(self, group): return GroupManagementScreen(self._groups_service, group) + + def create_groups_bans_screen(self, group): + return GroupBansScreen(self._groups_service, group) diff --git a/toxygen/utils/util.py b/toxygen/utils/util.py index 0f718ef..3c6910e 100644 --- a/toxygen/utils/util.py +++ b/toxygen/utils/util.py @@ -4,6 +4,7 @@ import shutil import sys import re import platform +import datetime def cached(func): @@ -21,10 +22,10 @@ def cached(func): def log(data): try: - with open(curr_directory() + '/logs.log', 'a') as fl: + with open(join_path(curr_directory(), 'logs.log'), 'a') as fl: fl.write(str(data) + '\n') - except: - pass + except Exception as ex: + print(ex) def curr_directory(current_file=None): @@ -144,6 +145,12 @@ def time_offset(): return result +def unix_time_to_long_str(unix_time): + date_time = datetime.datetime.utcfromtimestamp(unix_time) + + return date_time.strftime('%Y-%m-%d %H:%M:%S') + + @cached def is_64_bit(): return sys.maxsize > 2 ** 32 diff --git a/toxygen/wrapper/tox.py b/toxygen/wrapper/tox.py index 0e3310d..a2abf6a 100644 --- a/toxygen/wrapper/tox.py +++ b/toxygen/wrapper/tox.py @@ -2468,9 +2468,11 @@ class Tox: """ error = c_int() - result = Tox.libtoxcore.tox_group_ban_get_list(self._tox_pointer, group_number, POINTER(c_uint32)( - create_string_buffer(sizeof(c_uint32) * self.group_ban_get_list_size(group_number)), byref(error))) - return result + bans_list_size = self.group_ban_get_list_size(group_number) + bans_list = create_string_buffer(sizeof(c_uint32) * bans_list_size) + bans_list = POINTER(c_uint32)(bans_list) + result = Tox.libtoxcore.tox_group_ban_get_list(self._tox_pointer, group_number, bans_list, byref(error)) + return bans_list[:bans_list_size] def group_ban_get_target_size(self, group_number, ban_id): """ diff --git a/toxygen/wrapper/toxcore_enums_and_consts.py b/toxygen/wrapper/toxcore_enums_and_consts.py index 7c6478c..1e134f9 100644 --- a/toxygen/wrapper/toxcore_enums_and_consts.py +++ b/toxygen/wrapper/toxcore_enums_and_consts.py @@ -914,11 +914,11 @@ TOX_ERR_GROUP_BAN_QUERY = { TOX_GROUP_BAN_TYPE = { - 'TOX_GROUP_BAN_TYPE_IP_PORT': 0, + 'IP_PORT': 0, - 'TOX_GROUP_BAN_TYPE_PUBLIC_KEY': 1, + 'PUBLIC_KEY': 1, - 'TOX_GROUP_BAN_TYPE_NICK': 2 + 'NICK': 2 }