mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
fix #164 add MEMBER_REMOVED event and member_removed plugin python hook
This commit is contained in:
@@ -4522,6 +4522,15 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*/
|
||||
#define DC_EVENT_MEMBER_ADDED 2063
|
||||
|
||||
/**
|
||||
* This event is sent for each member that gets removed from a (verified or unverified) chat.
|
||||
*
|
||||
* @param data1 (int) chat_id
|
||||
* @param data2 (int) contact_id
|
||||
* @return 0
|
||||
*/
|
||||
#define DC_EVENT_MEMBER_REMOVED 2064
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -203,6 +203,10 @@ impl ContextWrapper {
|
||||
| Event::MemberAdded {
|
||||
chat_id,
|
||||
contact_id,
|
||||
}
|
||||
| Event::MemberRemoved {
|
||||
chat_id,
|
||||
contact_id,
|
||||
} => {
|
||||
ffi_cb(
|
||||
self,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from __future__ import print_function
|
||||
import atexit
|
||||
from contextlib import contextmanager
|
||||
import queue
|
||||
from threading import Event
|
||||
import os
|
||||
from array import array
|
||||
@@ -15,7 +16,6 @@ from .message import Message
|
||||
from .contact import Contact
|
||||
from .tracker import ImexTracker
|
||||
from . import hookspec, iothreads
|
||||
from queue import Queue
|
||||
|
||||
|
||||
class MissingCredentials(ValueError):
|
||||
@@ -49,7 +49,7 @@ class Account(object):
|
||||
hook.account_init(account=self, db_path=db_path)
|
||||
|
||||
self._threads = iothreads.IOThreads(self)
|
||||
self._hook_event_queue = Queue()
|
||||
self._hook_event_queue = queue.Queue()
|
||||
self._in_use_iter_events = False
|
||||
self._shutdown_event = Event()
|
||||
|
||||
@@ -578,6 +578,16 @@ class Account(object):
|
||||
hook = hookspec.Global._get_plugin_manager().hook
|
||||
hook.account_after_shutdown(account=self, dc_context=dc_context)
|
||||
|
||||
def _handle_current_events(self):
|
||||
""" handle all currently queued events and then return. """
|
||||
while 1:
|
||||
try:
|
||||
event = self._hook_event_queue.get(block=False)
|
||||
except queue.Empty:
|
||||
break
|
||||
else:
|
||||
event.call_hook()
|
||||
|
||||
def iter_events(self, timeout=None):
|
||||
""" yield hook events until shutdown.
|
||||
|
||||
@@ -614,6 +624,10 @@ class Account(object):
|
||||
chat = self.get_chat_by_id(ffi_event.data1)
|
||||
contact = self.get_contact_by_id(ffi_event.data2)
|
||||
return "member_added", dict(chat=chat, contact=contact)
|
||||
elif name == "DC_EVENT_MEMBER_REMOVED":
|
||||
chat = self.get_chat_by_id(ffi_event.data1)
|
||||
contact = self.get_contact_by_id(ffi_event.data2)
|
||||
return "member_removed", dict(chat=chat, contact=contact)
|
||||
return None, {}
|
||||
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060
|
||||
DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061
|
||||
DC_EVENT_SECUREJOIN_MEMBER_ADDED = 2062
|
||||
DC_EVENT_MEMBER_ADDED = 2063
|
||||
DC_EVENT_MEMBER_REMOVED = 2064
|
||||
DC_EVENT_FILE_COPIED = 2055
|
||||
DC_EVENT_IS_OFFLINE = 2081
|
||||
DC_EVENT_GET_STRING = 2091
|
||||
|
||||
@@ -56,6 +56,10 @@ class PerAccount:
|
||||
def member_added(self, chat, contact):
|
||||
""" Called for each contact added to a chat. """
|
||||
|
||||
@account_hookspec
|
||||
def member_removed(self, chat, contact):
|
||||
""" Called for each contact removed from a chat. """
|
||||
|
||||
|
||||
class Global:
|
||||
""" global hook specifications using a per-process singleton
|
||||
|
||||
@@ -438,20 +438,56 @@ class TestOfflineChat:
|
||||
def test_group_chat_many_members_add_remove(self, ac1, lp):
|
||||
lp.sec("ac1: creating group chat with 10 other members")
|
||||
chat = ac1.create_group_chat(name="title1")
|
||||
# promote chat
|
||||
chat.send_text("hello")
|
||||
assert chat.is_promoted()
|
||||
|
||||
# activate local plugin
|
||||
in_list = []
|
||||
|
||||
class InPlugin:
|
||||
@account_hookimpl
|
||||
def member_added(self, chat, contact):
|
||||
in_list.append(("added", chat, contact))
|
||||
|
||||
@account_hookimpl
|
||||
def member_removed(self, chat, contact):
|
||||
in_list.append(("removed", chat, contact))
|
||||
|
||||
ac1.add_account_plugin(InPlugin())
|
||||
|
||||
# perform add contact many times
|
||||
contacts = []
|
||||
for i in range(10):
|
||||
lp.sec("create contact")
|
||||
contact = ac1.create_contact("some{}@example.org".format(i))
|
||||
contacts.append(contact)
|
||||
lp.sec("add contact")
|
||||
chat.add_contact(contact)
|
||||
|
||||
num_contacts = len(chat.get_contacts())
|
||||
assert num_contacts == 11
|
||||
|
||||
# perform plugin hooks
|
||||
ac1._handle_current_events()
|
||||
|
||||
assert len(in_list) == 10
|
||||
for in_cmd, in_chat, in_contact in in_list:
|
||||
assert in_cmd == "added"
|
||||
assert in_chat == chat
|
||||
assert in_contact in contacts
|
||||
|
||||
lp.sec("ac1: removing two contacts and checking things are right")
|
||||
chat.remove_contact(contacts[9])
|
||||
chat.remove_contact(contacts[3])
|
||||
assert len(chat.get_contacts()) == 9
|
||||
|
||||
ac1._handle_current_events()
|
||||
assert len(in_list) == 12
|
||||
assert in_list[-2][0] == "removed"
|
||||
assert in_list[-2][1] == chat
|
||||
assert in_list[-2][2] == contacts[9]
|
||||
|
||||
|
||||
class TestOnlineAccount:
|
||||
def get_chat(self, ac1, ac2, both_created=False):
|
||||
@@ -1390,7 +1426,9 @@ class TestGroupStressTests:
|
||||
|
||||
lp.sec("ac2: removing one contact")
|
||||
to_remove = contacts[-1]
|
||||
|
||||
msg.chat.remove_contact(to_remove)
|
||||
ac2._evtracker.get_matching("DC_EVENT_MEMBER_REMOVED")
|
||||
|
||||
lp.sec("ac1: receiving system message about contact removal")
|
||||
sysmsg = ac1._evtracker.wait_next_incoming_message()
|
||||
|
||||
22
src/chat.rs
22
src/chat.rs
@@ -1953,20 +1953,22 @@ pub(crate) fn add_contact_to_chat_ex(
|
||||
msg.param.set_cmd(SystemMessage::MemberAddedToGroup);
|
||||
msg.param.set(Param::Arg, contact.get_addr());
|
||||
msg.param.set_int(Param::Arg2, from_handshake.into());
|
||||
|
||||
msg.id = send_msg(context, chat_id, &mut msg)?;
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id,
|
||||
msg_id: msg.id,
|
||||
});
|
||||
// send_msg sends MsgsChanged event
|
||||
// so we only send an explicit MemberAdded one
|
||||
context.call_cb(Event::MemberAdded {
|
||||
chat_id,
|
||||
contact_id: contact.id,
|
||||
});
|
||||
} else {
|
||||
// send an event for unpromoted groups
|
||||
// XXX probably not neccessary because ChatModified should suffice
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id,
|
||||
msg_id: MsgId::new(0),
|
||||
});
|
||||
}
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id,
|
||||
msg_id: MsgId::new(0),
|
||||
});
|
||||
context.call_cb(Event::ChatModified(chat_id));
|
||||
Ok(true)
|
||||
}
|
||||
@@ -2171,6 +2173,10 @@ pub fn remove_contact_from_chat(
|
||||
msg.param.set_cmd(SystemMessage::MemberRemovedFromGroup);
|
||||
msg.param.set(Param::Arg, contact.get_addr());
|
||||
msg.id = send_msg(context, chat_id, &mut msg)?;
|
||||
context.call_cb(Event::MemberRemoved {
|
||||
chat_id,
|
||||
contact_id: contact.id,
|
||||
});
|
||||
context.call_cb(Event::MsgsChanged {
|
||||
chat_id,
|
||||
msg_id: msg.id,
|
||||
|
||||
@@ -213,4 +213,10 @@ pub enum Event {
|
||||
/// @param data2 (int) contact_id
|
||||
#[strum(props(id = "2063"))]
|
||||
MemberAdded { chat_id: ChatId, contact_id: u32 },
|
||||
|
||||
/// This event is sent for each contact removed from a chat.
|
||||
/// @param data1 (int) chat_id
|
||||
/// @param data2 (int) contact_id
|
||||
#[strum(props(id = "2064"))]
|
||||
MemberRemoved { chat_id: ChatId, contact_id: u32 },
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user