mirror of
https://github.com/chatmail/core.git
synced 2026-05-14 20:36:30 +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
|
#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 {
|
| Event::MemberAdded {
|
||||||
chat_id,
|
chat_id,
|
||||||
contact_id,
|
contact_id,
|
||||||
|
}
|
||||||
|
| Event::MemberRemoved {
|
||||||
|
chat_id,
|
||||||
|
contact_id,
|
||||||
} => {
|
} => {
|
||||||
ffi_cb(
|
ffi_cb(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import atexit
|
import atexit
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
import queue
|
||||||
from threading import Event
|
from threading import Event
|
||||||
import os
|
import os
|
||||||
from array import array
|
from array import array
|
||||||
@@ -15,7 +16,6 @@ from .message import Message
|
|||||||
from .contact import Contact
|
from .contact import Contact
|
||||||
from .tracker import ImexTracker
|
from .tracker import ImexTracker
|
||||||
from . import hookspec, iothreads
|
from . import hookspec, iothreads
|
||||||
from queue import Queue
|
|
||||||
|
|
||||||
|
|
||||||
class MissingCredentials(ValueError):
|
class MissingCredentials(ValueError):
|
||||||
@@ -49,7 +49,7 @@ class Account(object):
|
|||||||
hook.account_init(account=self, db_path=db_path)
|
hook.account_init(account=self, db_path=db_path)
|
||||||
|
|
||||||
self._threads = iothreads.IOThreads(self)
|
self._threads = iothreads.IOThreads(self)
|
||||||
self._hook_event_queue = Queue()
|
self._hook_event_queue = queue.Queue()
|
||||||
self._in_use_iter_events = False
|
self._in_use_iter_events = False
|
||||||
self._shutdown_event = Event()
|
self._shutdown_event = Event()
|
||||||
|
|
||||||
@@ -578,6 +578,16 @@ class Account(object):
|
|||||||
hook = hookspec.Global._get_plugin_manager().hook
|
hook = hookspec.Global._get_plugin_manager().hook
|
||||||
hook.account_after_shutdown(account=self, dc_context=dc_context)
|
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):
|
def iter_events(self, timeout=None):
|
||||||
""" yield hook events until shutdown.
|
""" yield hook events until shutdown.
|
||||||
|
|
||||||
@@ -614,6 +624,10 @@ class Account(object):
|
|||||||
chat = self.get_chat_by_id(ffi_event.data1)
|
chat = self.get_chat_by_id(ffi_event.data1)
|
||||||
contact = self.get_contact_by_id(ffi_event.data2)
|
contact = self.get_contact_by_id(ffi_event.data2)
|
||||||
return "member_added", dict(chat=chat, contact=contact)
|
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, {}
|
return None, {}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060
|
|||||||
DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061
|
DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061
|
||||||
DC_EVENT_SECUREJOIN_MEMBER_ADDED = 2062
|
DC_EVENT_SECUREJOIN_MEMBER_ADDED = 2062
|
||||||
DC_EVENT_MEMBER_ADDED = 2063
|
DC_EVENT_MEMBER_ADDED = 2063
|
||||||
|
DC_EVENT_MEMBER_REMOVED = 2064
|
||||||
DC_EVENT_FILE_COPIED = 2055
|
DC_EVENT_FILE_COPIED = 2055
|
||||||
DC_EVENT_IS_OFFLINE = 2081
|
DC_EVENT_IS_OFFLINE = 2081
|
||||||
DC_EVENT_GET_STRING = 2091
|
DC_EVENT_GET_STRING = 2091
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ class PerAccount:
|
|||||||
def member_added(self, chat, contact):
|
def member_added(self, chat, contact):
|
||||||
""" Called for each contact added to a chat. """
|
""" 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:
|
class Global:
|
||||||
""" global hook specifications using a per-process singleton
|
""" 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):
|
def test_group_chat_many_members_add_remove(self, ac1, lp):
|
||||||
lp.sec("ac1: creating group chat with 10 other members")
|
lp.sec("ac1: creating group chat with 10 other members")
|
||||||
chat = ac1.create_group_chat(name="title1")
|
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 = []
|
contacts = []
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
|
lp.sec("create contact")
|
||||||
contact = ac1.create_contact("some{}@example.org".format(i))
|
contact = ac1.create_contact("some{}@example.org".format(i))
|
||||||
contacts.append(contact)
|
contacts.append(contact)
|
||||||
|
lp.sec("add contact")
|
||||||
chat.add_contact(contact)
|
chat.add_contact(contact)
|
||||||
|
|
||||||
num_contacts = len(chat.get_contacts())
|
num_contacts = len(chat.get_contacts())
|
||||||
assert num_contacts == 11
|
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")
|
lp.sec("ac1: removing two contacts and checking things are right")
|
||||||
chat.remove_contact(contacts[9])
|
chat.remove_contact(contacts[9])
|
||||||
chat.remove_contact(contacts[3])
|
chat.remove_contact(contacts[3])
|
||||||
assert len(chat.get_contacts()) == 9
|
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:
|
class TestOnlineAccount:
|
||||||
def get_chat(self, ac1, ac2, both_created=False):
|
def get_chat(self, ac1, ac2, both_created=False):
|
||||||
@@ -1390,7 +1426,9 @@ class TestGroupStressTests:
|
|||||||
|
|
||||||
lp.sec("ac2: removing one contact")
|
lp.sec("ac2: removing one contact")
|
||||||
to_remove = contacts[-1]
|
to_remove = contacts[-1]
|
||||||
|
|
||||||
msg.chat.remove_contact(to_remove)
|
msg.chat.remove_contact(to_remove)
|
||||||
|
ac2._evtracker.get_matching("DC_EVENT_MEMBER_REMOVED")
|
||||||
|
|
||||||
lp.sec("ac1: receiving system message about contact removal")
|
lp.sec("ac1: receiving system message about contact removal")
|
||||||
sysmsg = ac1._evtracker.wait_next_incoming_message()
|
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_cmd(SystemMessage::MemberAddedToGroup);
|
||||||
msg.param.set(Param::Arg, contact.get_addr());
|
msg.param.set(Param::Arg, contact.get_addr());
|
||||||
msg.param.set_int(Param::Arg2, from_handshake.into());
|
msg.param.set_int(Param::Arg2, from_handshake.into());
|
||||||
|
|
||||||
msg.id = send_msg(context, chat_id, &mut msg)?;
|
msg.id = send_msg(context, chat_id, &mut msg)?;
|
||||||
context.call_cb(Event::MsgsChanged {
|
// send_msg sends MsgsChanged event
|
||||||
chat_id,
|
// so we only send an explicit MemberAdded one
|
||||||
msg_id: msg.id,
|
|
||||||
});
|
|
||||||
context.call_cb(Event::MemberAdded {
|
context.call_cb(Event::MemberAdded {
|
||||||
chat_id,
|
chat_id,
|
||||||
contact_id: contact.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));
|
context.call_cb(Event::ChatModified(chat_id));
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
@@ -2171,6 +2173,10 @@ pub fn remove_contact_from_chat(
|
|||||||
msg.param.set_cmd(SystemMessage::MemberRemovedFromGroup);
|
msg.param.set_cmd(SystemMessage::MemberRemovedFromGroup);
|
||||||
msg.param.set(Param::Arg, contact.get_addr());
|
msg.param.set(Param::Arg, contact.get_addr());
|
||||||
msg.id = send_msg(context, chat_id, &mut msg)?;
|
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 {
|
context.call_cb(Event::MsgsChanged {
|
||||||
chat_id,
|
chat_id,
|
||||||
msg_id: msg.id,
|
msg_id: msg.id,
|
||||||
|
|||||||
@@ -213,4 +213,10 @@ pub enum Event {
|
|||||||
/// @param data2 (int) contact_id
|
/// @param data2 (int) contact_id
|
||||||
#[strum(props(id = "2063"))]
|
#[strum(props(id = "2063"))]
|
||||||
MemberAdded { chat_id: ChatId, contact_id: u32 },
|
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