diff frontends/src/quick_frontend/quick_chat.py @ 1955:633b5c21aefd

backend, frontend: messages refactoring (huge commit, not finished): /!\ database schema has been modified, do a backup before updating message have been refactored, here are the main changes: - languages are now handled - all messages have an uid (internal to SàT) - message updating is anticipated - subject is now first class - new naming scheme is used newMessage => messageNew, getHistory => historyGet, sendMessage => messageSend - minimal compatibility refactoring in quick_frontend/Primitivus, better refactoring should follow - threads handling - delayed messages are saved into history - info messages may also be saved in history (e.g. to keep track of people joining/leaving a room) - duplicate messages should be avoided - historyGet return messages in right order, no need to sort again - plugins have been updated to follow new features, some of them need to be reworked (e.g. OTR) - XEP-0203 (Delayed Delivery) is now fully handled in core, the plugin just handle disco and creation of a delay element - /!\ jp and Libervia are currently broken, as some features of Primitivus It has been put in one huge commit to avoid breaking messaging between changes. This is the main part of message refactoring, other commits will follow to take profit of the new features/behaviour.
author Goffi <goffi@goffi.org>
date Tue, 24 May 2016 22:11:04 +0200
parents 2daf7b4c6756
children a2bc5089c2eb
line wrap: on
line diff
--- a/frontends/src/quick_frontend/quick_chat.py	Mon Apr 18 18:35:19 2016 +0200
+++ b/frontends/src/quick_frontend/quick_chat.py	Tue May 24 22:11:04 2016 +0200
@@ -25,7 +25,6 @@
 from sat_frontends.quick_frontend.constants import Const as C
 from collections import OrderedDict
 from datetime import datetime
-from time import time
 
 try:
     # FIXME: to be removed when an acceptable solution is here
@@ -52,18 +51,15 @@
         self.nick = None
         self.games = {}  # key=game name (unicode), value=instance of quick_games.RoomGame
 
-        if type_ == C.CHAT_ONE2ONE:
-            self.historyPrint(profile=self.profile)
-
-        # FIXME: has been introduced to temporarily fix http://bugs.goffi.org/show_bug.cgi?id=12
-        self.initialised = False
+        self.historyPrint(profile=self.profile)
 
     def __str__(self):
         return u"Chat Widget [target: {}, type: {}, profile: {}]".format(self.target, self.type, self.profile)
 
     @staticmethod
-    def getWidgetHash(target, profile):
-        return (unicode(profile), target.bare)
+    def getWidgetHash(target, profiles):
+        profile = profiles[0]
+        return (profile, target.bare)
 
     @staticmethod
     def getPrivateHash(target, profile):
@@ -99,7 +95,7 @@
         """Tell if this chat widget manage an entity and message type couple
 
         @param entity (jid.JID): (full) jid of the sending entity
-        @param mess_type (str): message type as given by newMessage
+        @param mess_type (str): message type as given by messageNew
         @return (bool): True if this Chat Widget manage this couple
         """
         if self.type == C.CHAT_GROUP:
@@ -112,8 +108,6 @@
 
     def addUser(self, nick):
         """Add user if it is not in the group list"""
-        if not self.initialised:
-            return  # FIXME: tmp fix for bug 12, do not flood the room with the messages when we've just entered it
         self.printInfo("=> %s has joined the room" % nick)
 
     def removeUser(self, nick):
@@ -141,6 +135,7 @@
 
     def historyPrint(self, size=C.HISTORY_LIMIT_DEFAULT, search='', profile='@NONE@'):
         """Print the current history
+
         @param size (int): number of messages
         @param search (str): pattern to filter the history results
         @param profile (str): %(doc_profile)s
@@ -152,28 +147,26 @@
 
         target = self.target.bare
 
-        def onHistory(history):
-            self.initialised = True  # FIXME: tmp fix for bug 12
+        def _historyGetCb(history):
             day_format = "%A, %d %b %Y"  # to display the day change
             previous_day = datetime.now().strftime(day_format)
-            for line in history:
-                timestamp, from_jid, to_jid, message, type_, extra = line  # FIXME: extra is unused !
+            for data in history:
+                uid, timestamp, from_jid, to_jid, message, subject, type_, extra = data  # FIXME: extra is unused !
                 if ((self.type == C.CHAT_GROUP and type_ != C.MESS_TYPE_GROUPCHAT) or
                    (self.type == C.CHAT_ONE2ONE and type_ == C.MESS_TYPE_GROUPCHAT)):
                     continue
-                message_day = datetime.fromtimestamp(float(timestamp or time())).strftime(day_format)
+                message_day = datetime.fromtimestamp(timestamp).strftime(day_format)
                 if previous_day != message_day:
                     self.printDayChange(message_day)
                     previous_day = message_day
                 extra["timestamp"] = timestamp
-                self.newMessage(jid.JID(from_jid), target, message, type_, extra, profile)
+                self.messageNew(uid, timestamp, jid.JID(from_jid), target, message, subject, type_, extra, profile)
             self.afterHistoryPrint()
 
-        def onHistoryError(err):
+        def _historyGetEb(err):
             log.error(_("Can't get history"))
 
-        self.initialised = False  # FIXME: tmp fix for bug 12, here needed for :history and :search commands
-        self.host.bridge.getHistory(unicode(self.host.profiles[profile].whoami.bare), unicode(target), size, True, search, profile, callback=onHistory, errback=onHistoryError)
+        self.host.bridge.historyGet(unicode(self.host.profiles[profile].whoami.bare), unicode(target), size, True, search, profile, callback=_historyGetCb, errback=_historyGetEb)
 
     def _get_nick(self, entity):
         """Return nick of this entity when possible"""
@@ -195,34 +188,31 @@
         """
         return self.host.widgets.getOrCreateWidget(QuickChat, entity, type_=C.CHAT_ONE2ONE, force_hash=self.getPrivateHash(self.profile, entity), on_new_widget=self.onPrivateCreated, profile=self.profile) # we force hash to have a new widget, not this one again
 
-    def newMessage(self, from_jid, target, msg, type_, extra, profile):
+    def messageNew(self, uid, timestamp, from_jid, target, msg, subject, type_, extra, profile):
+        try:
+            msg = msg.itervalues().next() # FIXME: tmp fix until message refactoring is finished (msg is now a dict)
+        except StopIteration:
+            log.warning(u"No message found (uid: {})".format(uid))
+            msg = ''
         if self.type == C.CHAT_GROUP and target.resource and type_ != C.MESS_TYPE_GROUPCHAT:
             # we have a private message, we forward it to a private conversation widget
             chat_widget = self.getOrCreatePrivateWidget(target)
-            chat_widget.newMessage(from_jid, target, msg, type_, extra, profile)
+            chat_widget.messageNew(uid, timestamp, from_jid, target, msg, subject, type_, extra, profile)
             return
-        try:
-            timestamp = float(extra['timestamp'])
-        except KeyError:
-            timestamp = None
-
-        if not self.initialised and self.type == C.CHAT_ONE2ONE:
-            return  # FIXME: tmp fix for bug 12, do not display the first one2one message which is already in the local history
 
         if type_ == C.MESS_TYPE_INFO:
             self.printInfo(msg, extra=extra)
         else:
-            self.initialised = True  # FIXME: tmp fix for bug 12, do not discard any message from now
-
             nick = self._get_nick(from_jid)
             if msg.startswith('/me '):
-                self.printInfo('* %s %s' % (nick, msg[4:]), type_='me', extra=extra)
+                self.printInfo('* {} {}'.format(nick, msg[4:]), type_='me', extra=extra)
             else:
                 # my_message is True if message comes from local user
                 my_message = (from_jid.resource == self.nick) if self.type == C.CHAT_GROUP else (from_jid.bare == self.host.profiles[profile].whoami.bare)
                 self.printMessage(nick, my_message, msg, timestamp, extra, profile)
-        if timestamp:
-            self.afterHistoryPrint()
+        # FIXME: to be checked/removed after message refactoring
+        # if timestamp:
+        self.afterHistoryPrint()
 
     def printMessage(self, nick, my_message, message, timestamp, extra=None, profile=C.PROF_KEY_NONE):
         """Print message in chat window.
@@ -232,11 +222,12 @@
         @param message (unicode): message content
         @param extra (dict): extra data
         """
-        if not timestamp:
-            # XXX: do not send notifications for each line of the history being displayed
-            # FIXME: this must be changed in the future if the timestamp is passed with
-            # all messages and not only with the messages coming from the history.
-            self.notify(nick, message)
+        # FIXME: check/remove this if necessary (message refactoring)
+        # if not timestamp:
+        #     # XXX: do not send notifications for each line of the history being displayed
+        #     # FIXME: this must be changed in the future if the timestamp is passed with
+        #     # all messages and not only with the messages coming from the history.
+        self.notify(nick, message)
 
     def printInfo(self, msg, type_='normal', extra=None):
         """Print general info.