Fix join room, inform user of all groups, and new participants
In the previous implementation join_room was called on all groups immediately after the user was authenticated. When a user joined a group, join_room will be called again. This was incorrect behaviour and confused spectrum. There was no truncation error, thus _shortenGroupId and _lengthenGroupId have edited to be a no-op (and should be removed in the next commit). The correct behavoiur is to only call join_room in whatsappbackend.py:handleRoomJoined, however the user may do this before the groups have been loaded, in which case those requests must be added to a queue. The bot informs the user of all the groups the user has joined and when the user is added to a new group.
This commit is contained in:
parent
744efd154f
commit
1c0ae79ec2
100
session.py
100
session.py
|
@ -52,6 +52,8 @@ class Session(YowsupApp):
|
|||
self.statusMessage = ''
|
||||
|
||||
self.groups = {}
|
||||
self.gotGroupList = False
|
||||
self.joinRoomQueue = []
|
||||
self.presenceRequested = []
|
||||
self.offlineQueue = []
|
||||
self.groupOfflineQueue = { }
|
||||
|
@ -79,20 +81,27 @@ class Session(YowsupApp):
|
|||
super(Session, self).login(self.legacyName, self.password)
|
||||
|
||||
def _shortenGroupId(self, gid):
|
||||
# FIXME: will have problems if number begins with 0
|
||||
return '-'.join(hex(int(s))[2:] for s in gid.split('-'))
|
||||
|
||||
# FIXME: might have problems if number begins with 0
|
||||
return gid
|
||||
# return '-'.join(hex(int(s))[2:] for s in gid.split('-'))
|
||||
|
||||
def _lengthenGroupId(self, gid):
|
||||
# FIXME: will have problems if number begins with 0
|
||||
return '-'.join(str(int(s, 16)) for s in gid.split('-'))
|
||||
return gid
|
||||
# FIXME: might have problems if number begins with 0
|
||||
# return '-'.join(str(int(s, 16)) for s in gid.split('-'))
|
||||
|
||||
def updateRoomList(self):
|
||||
rooms = []
|
||||
text = []
|
||||
for room, group in self.groups.iteritems():
|
||||
rooms.append([self._shortenGroupId(room), group.subject])
|
||||
text.append(self._shortenGroupId(room) + '@' + self.backend.spectrum_jid + ' :' + group.subject)
|
||||
|
||||
self.logger.debug("Got rooms: %s", rooms)
|
||||
self.backend.handleRoomList(rooms)
|
||||
message = "Note, you are a participant of the following groups:\n" +\
|
||||
'\n'.join(text) + '\nIf you do not join them you will lose messages'
|
||||
self.bot.send(message)
|
||||
|
||||
def updateRoster(self):
|
||||
self.logger.debug("Update roster")
|
||||
|
@ -143,9 +152,10 @@ class Session(YowsupApp):
|
|||
oroom.subject = subject
|
||||
else:
|
||||
self.groups[room] = Group(room, owner, subject, subjectOwner)
|
||||
self.joinRoom(self._shortenGroupId(room), self.user.split("@")[0])
|
||||
# self.joinRoom(self._shortenGroupId(room), self.user.split("@")[0])
|
||||
self.groups[room].participants = group.getParticipants().keys()
|
||||
|
||||
self._addParticipantsToRoom(room, group.getParticipants())
|
||||
#self._addParticipantsToRoom(room, group.getParticipants())
|
||||
|
||||
if room in self.groupOfflineQueue:
|
||||
while self.groupOfflineQueue[room]:
|
||||
|
@ -154,9 +164,16 @@ class Session(YowsupApp):
|
|||
msg[0], "", msg[2])
|
||||
self.logger.debug("Send queued group message to: %s %s %s",
|
||||
msg[0],msg[1], msg[2])
|
||||
self.gotGroupList = True
|
||||
for room, nick in self.joinRoomQueue:
|
||||
self.joinRoom(room, nick)
|
||||
self.joinRoomQueue = []
|
||||
self.updateRoomList()
|
||||
|
||||
def joinRoom(self, room, nick):
|
||||
if not self.gotGroupList:
|
||||
self.joinRoomQueue.append((room, nick))
|
||||
return
|
||||
room = self._lengthenGroupId(room)
|
||||
if room in self.groups:
|
||||
self.logger.info("Joining room: %s room=%s, nick=%s",
|
||||
|
@ -169,13 +186,14 @@ class Session(YowsupApp):
|
|||
except KeyError:
|
||||
ownerNick = group.subjectOwner
|
||||
|
||||
self._refreshParticipants(room)
|
||||
self.backend.handleSubject(self.user, self._shortenGroupId(room),
|
||||
group.subject,
|
||||
ownerNick)
|
||||
group.subject)
|
||||
self.logger.debug("Room subject: room=%s, subject=%s",
|
||||
room, group.subject)
|
||||
self.backend.handleRoomNicknameChanged(
|
||||
self.user, self._shortenGroupId(room), group.subject
|
||||
)
|
||||
self._refreshParticipants(room)
|
||||
else:
|
||||
self.logger.warn("Room doesn't exist: %s", room)
|
||||
|
||||
|
@ -191,7 +209,6 @@ class Session(YowsupApp):
|
|||
if nick == "":
|
||||
nick = buddy
|
||||
|
||||
buddyFull = buddy
|
||||
if buddy == group.owner:
|
||||
flags = protocol_pb2.PARTICIPANT_FLAG_MODERATOR
|
||||
else:
|
||||
|
@ -199,38 +216,9 @@ class Session(YowsupApp):
|
|||
if buddy == self.legacyName:
|
||||
nick = group.nick
|
||||
flags = flags | protocol_pb2.PARTICIPANT_FLAG_ME
|
||||
buddyFull = self.user
|
||||
self.backend.handleParticipantChanged(
|
||||
self.user, buddyFull, self._shortenGroupId(room), flags,
|
||||
protocol_pb2.STATUS_ONLINE, buddy, nick)
|
||||
|
||||
def _addParticipantsToRoom(self, room, participants):
|
||||
group = self.groups[room]
|
||||
group.participants = participants
|
||||
|
||||
for jid, _type in participants.iteritems():
|
||||
buddy = jid.split("@")[0]
|
||||
buddyFull = buddy
|
||||
self.logger.info("Added %s to room %s", buddy, room)
|
||||
try:
|
||||
nick = self.buddies[buddy].nick
|
||||
except KeyError:
|
||||
nick = buddy
|
||||
buddyFull = buddy
|
||||
if _type == 'admin':
|
||||
flags = protocol_pb2.PARTICIPANT_FLAG_MODERATOR
|
||||
else:
|
||||
flags = protocol_pb2.PARTICIPANT_FLAG_NONE
|
||||
if buddy == self.legacyName:
|
||||
nick = group.nick
|
||||
flags = protocol_pb2.PARTICIPANT_FLAG_ME
|
||||
buddyFull = self.user
|
||||
|
||||
self.backend.handleParticipantChanged(
|
||||
self.user, buddyFull, self._shortenGroupId(room), flags,
|
||||
protocol_pb2.STATUS_ONLINE, buddy, nick
|
||||
)
|
||||
|
||||
self.user, nick, self._shortenGroupId(room), flags,
|
||||
protocol_pb2.STATUS_ONLINE, buddy)
|
||||
|
||||
def _lastSeen(self, number, seconds):
|
||||
self.logger.debug("Last seen %s at %s seconds" % (number, str(seconds)))
|
||||
|
@ -309,9 +297,9 @@ class Session(YowsupApp):
|
|||
if part.nick == "":
|
||||
part.nick = notify
|
||||
self.backend.handleParticipantChanged(
|
||||
self.user, partname, buddy,
|
||||
self.user, partname, self._shortenGroupId(buddy),
|
||||
protocol_pb2.PARTICIPANT_FLAG_NONE,
|
||||
protocol_pb2.STATUS_NONE, "", part.nick
|
||||
protocol_pb2.STATUS_ONLINE, "", part.nick
|
||||
) # TODO
|
||||
except KeyError:
|
||||
self.updateBuddy(partname, notify, [])
|
||||
|
@ -402,6 +390,28 @@ class Session(YowsupApp):
|
|||
self.timer = Timer(3, self.backend.handleBuddyStoppedTyping,
|
||||
(self.user, buddy)).start()
|
||||
|
||||
# Called by superclass
|
||||
def onAddedToGroup(self, group):
|
||||
self.logger.debug("Added to group: %s", group)
|
||||
room = group.getGroupId()
|
||||
owner = group.getCreatorJid(full = False)
|
||||
subjectOwner = group.getSubjectOwnerJid(full = False)
|
||||
subject = utils.softToUni(group.getSubject())
|
||||
|
||||
self.groups[room] = Group(room, owner, subject, subjectOwner)
|
||||
self.groups[room].participants = group.getParticipants().keys()
|
||||
# self.joinRoom(self._shortenGroupId(room), self.user.split("@")[0])
|
||||
|
||||
#self._addParticipantsToRoom(room, group.getParticipants())
|
||||
self.bot.send("You have been added to group: %s@%s (%s)"
|
||||
% (self._shortenGroupId(room), subject, self.backend.spectrum_jid))
|
||||
|
||||
def onParticipantsAddedToGroup(self, group):
|
||||
self.logger.debug("Participants added to group: %s", group)
|
||||
room = group.getGroupId().split('@')[0]
|
||||
self.groups[room].participants.extend(group.getParticipants())
|
||||
self._refreshParticipants(room)
|
||||
|
||||
def onPresenceReceived(self, _type, name, jid, lastseen):
|
||||
self.logger.info("Presence received: %s %s %s %s", _type, name, jid, lastseen)
|
||||
buddy = jid.split("@")[0]
|
||||
|
@ -504,7 +514,7 @@ class Session(YowsupApp):
|
|||
"", timestamp)
|
||||
|
||||
def sendGroupMessageToXMPP(self, room, buddy, messageContent, timestamp = ""):
|
||||
self._refreshParticipants(room)
|
||||
# self._refreshParticipants(room)
|
||||
try:
|
||||
nick = self.buddies[buddy].nick
|
||||
except KeyError:
|
||||
|
|
|
@ -78,7 +78,7 @@ def connectionClosed():
|
|||
db = MySQLdb.connect(DB_HOST, DB_USER, DB_PASS, DB_TABLE)
|
||||
io = IOChannel(args.host, args.port, handleTransportData, connectionClosed)
|
||||
|
||||
plugin = WhatsAppBackend(io, db)
|
||||
plugin = WhatsAppBackend(io, db, args.j)
|
||||
|
||||
while True:
|
||||
try:
|
||||
|
|
|
@ -30,12 +30,13 @@ from session import Session
|
|||
import logging
|
||||
|
||||
class WhatsAppBackend(SpectrumBackend):
|
||||
def __init__(self, io, db):
|
||||
def __init__(self, io, db, spectrum_jid):
|
||||
SpectrumBackend.__init__(self)
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
self.io = io
|
||||
self.db = db
|
||||
self.sessions = { }
|
||||
self.spectrum_jid = spectrum_jid
|
||||
# Used to prevent duplicate messages
|
||||
self.lastMessage = {}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import logging
|
||||
|
||||
from yowsup import env
|
||||
from yowsup.stacks import YowStack
|
||||
from yowsup.common import YowConstants
|
||||
|
@ -67,6 +69,7 @@ class YowsupApp(object):
|
|||
YowStanzaRegulator,
|
||||
YowNetworkLayer
|
||||
)
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
self.stack = YowStack(layers)
|
||||
self.stack.broadcastEvent(
|
||||
YowLayerEvent(YowsupAppLayer.EVENT_START, caller = self)
|
||||
|
@ -108,7 +111,7 @@ class YowsupApp(object):
|
|||
Logout from whatsapp
|
||||
"""
|
||||
self.stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT))
|
||||
|
||||
|
||||
def sendReceipt(self, _id, _from, read, participant):
|
||||
"""
|
||||
Send a receipt (delivered: double-tick, read: blue-ticks)
|
||||
|
@ -168,7 +171,7 @@ class YowsupApp(object):
|
|||
jid = phone_number + '@s.whatsapp.net'
|
||||
entity = UnsubscribePresenceProtocolEntity(jid)
|
||||
self.sendEntity(entity)
|
||||
|
||||
|
||||
def setStatus(self, statusText):
|
||||
"""
|
||||
Send status to whatsapp
|
||||
|
@ -313,7 +316,7 @@ class YowsupApp(object):
|
|||
- timestamp
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def onPresenceReceived(self, _type, name, _from, last):
|
||||
"""
|
||||
Called when presence (e.g. available, unavailable) is received
|
||||
|
@ -331,7 +334,7 @@ class YowsupApp(object):
|
|||
"""
|
||||
Called when disconnected from whatsapp
|
||||
"""
|
||||
|
||||
|
||||
def onContactTyping(self, number):
|
||||
"""
|
||||
Called when contact starts to type
|
||||
|
@ -366,7 +369,7 @@ class YowsupApp(object):
|
|||
- body: The content of the message
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def onImage(self, entity):
|
||||
"""
|
||||
Called when image message is received
|
||||
|
@ -384,7 +387,7 @@ class YowsupApp(object):
|
|||
- entity: AudioDownloadableMediaMessageProtocolEntity
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def onVideo(self, entity):
|
||||
"""
|
||||
|
@ -403,7 +406,7 @@ class YowsupApp(object):
|
|||
- entity: LocationMediaMessageProtocolEntity
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def onVCard(self, _id, _from, name, card_data, to, notify, timestamp, participant):
|
||||
"""
|
||||
Called when VCard message is received
|
||||
|
@ -420,12 +423,20 @@ class YowsupApp(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
def onAddedToGroup(self, entity):
|
||||
"""Called when the user has been added to a new group"""
|
||||
pass
|
||||
|
||||
def onParticipantsAddedToGroup(self, entity):
|
||||
"""Called when participants have been added to a group"""
|
||||
pass
|
||||
|
||||
def sendEntity(self, entity):
|
||||
"""Sends an entity down the stack (as if YowsupAppLayer called toLower)"""
|
||||
self.stack.broadcastEvent(YowLayerEvent(YowsupAppLayer.TO_LOWER_EVENT,
|
||||
entity = entity
|
||||
))
|
||||
|
||||
|
||||
def sendIq(self, iq, onSuccess = None, onError = None):
|
||||
self.stack.broadcastEvent(
|
||||
YowLayerEvent(
|
||||
|
@ -450,6 +461,7 @@ class YowsupAppLayer(YowInterfaceLayer):
|
|||
# return True otherwise
|
||||
if layerEvent.getName() == YowsupAppLayer.EVENT_START:
|
||||
self.caller = layerEvent.getArg('caller')
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
return True
|
||||
elif layerEvent.getName() == YowNetworkLayer.EVENT_STATE_DISCONNECTED:
|
||||
self.caller.onDisconnect()
|
||||
|
@ -514,8 +526,13 @@ class YowsupAppLayer(YowInterfaceLayer):
|
|||
"""
|
||||
Sends ack automatically
|
||||
"""
|
||||
self.logger.debug("Received notification: %s", entity)
|
||||
self.toLower(entity.ack())
|
||||
|
||||
if isinstance(entity, CreateGroupsNotificationProtocolEntity):
|
||||
self.caller.onAddedToGroup(entity)
|
||||
elif isinstance(entity, AddGroupsNotificationProtocolEntity):
|
||||
self.caller.onParticipantsAddedToGroup(entity)
|
||||
|
||||
@ProtocolEntityCallback('message')
|
||||
def onMessageReceived(self, entity):
|
||||
if entity.getType() == MessageProtocolEntity.MESSAGE_TYPE_TEXT:
|
||||
|
@ -560,7 +577,7 @@ class YowsupAppLayer(YowInterfaceLayer):
|
|||
_from = presence.getFrom()
|
||||
last = presence.getLast()
|
||||
self.caller.onPresenceReceived(_type, name, _from, last)
|
||||
|
||||
|
||||
@ProtocolEntityCallback('chatstate')
|
||||
def onChatstate(self, chatstate):
|
||||
number = chatstate._from.split('@')[0]
|
||||
|
|
Loading…
Reference in a new issue