comparison sat_frontends/quick_frontend/quick_chat.py @ 2624:56f94936df1e

code style reformatting using black
author Goffi <goffi@goffi.org>
date Wed, 27 Jun 2018 20:14:46 +0200
parents 5e54afd17321
children 96911768b0f3
comparison
equal deleted inserted replaced
2623:49533de4540b 2624:56f94936df1e
17 # You should have received a copy of the GNU Affero General Public License 17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20 from sat.core.i18n import _ 20 from sat.core.i18n import _
21 from sat.core.log import getLogger 21 from sat.core.log import getLogger
22
22 log = getLogger(__name__) 23 log = getLogger(__name__)
23 from sat.core import exceptions 24 from sat.core import exceptions
24 from sat_frontends.quick_frontend import quick_widgets 25 from sat_frontends.quick_frontend import quick_widgets
25 from sat_frontends.quick_frontend.constants import Const as C 26 from sat_frontends.quick_frontend.constants import Const as C
26 from collections import OrderedDict 27 from collections import OrderedDict
27 from sat_frontends.tools import jid 28 from sat_frontends.tools import jid
28 import time 29 import time
30
29 try: 31 try:
30 from locale import getlocale 32 from locale import getlocale
31 except ImportError: 33 except ImportError:
32 # FIXME: pyjamas workaround 34 # FIXME: pyjamas workaround
33 getlocale = lambda x: (None, 'utf-8') 35 getlocale = lambda x: (None, "utf-8")
34 36
35 37
36 ROOM_USER_JOINED = 'ROOM_USER_JOINED' 38 ROOM_USER_JOINED = "ROOM_USER_JOINED"
37 ROOM_USER_LEFT = 'ROOM_USER_LEFT' 39 ROOM_USER_LEFT = "ROOM_USER_LEFT"
38 ROOM_USER_MOVED = (ROOM_USER_JOINED, ROOM_USER_LEFT) 40 ROOM_USER_MOVED = (ROOM_USER_JOINED, ROOM_USER_LEFT)
39 41
40 # from datetime import datetime 42 # from datetime import datetime
41 43
42 try: 44 try:
43 # FIXME: to be removed when an acceptable solution is here 45 # FIXME: to be removed when an acceptable solution is here
44 unicode('') # XXX: unicode doesn't exist in pyjamas 46 unicode("") # XXX: unicode doesn't exist in pyjamas
45 except (TypeError, AttributeError): # Error raised is not the same depending on pyjsbuild options 47 except (
48 TypeError,
49 AttributeError,
50 ): # Error raised is not the same depending on pyjsbuild options
46 unicode = str 51 unicode = str
47 52
48 # FIXME: day_format need to be settable (i18n) 53 # FIXME: day_format need to be settable (i18n)
54
49 55
50 class Message(object): 56 class Message(object):
51 """Message metadata""" 57 """Message metadata"""
52 58
53 def __init__(self, parent, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile): 59 def __init__(
60 self,
61 parent,
62 uid,
63 timestamp,
64 from_jid,
65 to_jid,
66 msg,
67 subject,
68 type_,
69 extra,
70 profile,
71 ):
54 self.parent = parent 72 self.parent = parent
55 self.profile = profile 73 self.profile = profile
56 self.uid = uid 74 self.uid = uid
57 self.timestamp = timestamp 75 self.timestamp = timestamp
58 self.from_jid = from_jid 76 self.from_jid = from_jid
62 self.type = type_ 80 self.type = type_
63 self.extra = extra 81 self.extra = extra
64 self.nick = self.getNick(from_jid) 82 self.nick = self.getNick(from_jid)
65 self._status = None 83 self._status = None
66 # own_mess is True if message was sent by profile's jid 84 # own_mess is True if message was sent by profile's jid
67 self.own_mess = (from_jid.resource == self.parent.nick) if self.parent.type == C.CHAT_GROUP else (from_jid.bare == self.host.profiles[profile].whoami.bare) 85 self.own_mess = (
86 (from_jid.resource == self.parent.nick)
87 if self.parent.type == C.CHAT_GROUP
88 else (from_jid.bare == self.host.profiles[profile].whoami.bare)
89 )
68 # is user mentioned here ? 90 # is user mentioned here ?
69 if self.parent.type == C.CHAT_GROUP and not self.own_mess: 91 if self.parent.type == C.CHAT_GROUP and not self.own_mess:
70 for m in msg.itervalues(): 92 for m in msg.itervalues():
71 if self.parent.nick.lower() in m.lower(): 93 if self.parent.nick.lower() in m.lower():
72 self._mention = True 94 self._mention = True
78 def host(self): 100 def host(self):
79 return self.parent.host 101 return self.parent.host
80 102
81 @property 103 @property
82 def info_type(self): 104 def info_type(self):
83 return self.extra.get('info_type') 105 return self.extra.get("info_type")
84 106
85 @property 107 @property
86 def mention(self): 108 def mention(self):
87 try: 109 try:
88 return self._mention 110 return self._mention
90 return False 112 return False
91 113
92 @property 114 @property
93 def history(self): 115 def history(self):
94 """True if message come from history""" 116 """True if message come from history"""
95 return self.extra.get('history', False) 117 return self.extra.get("history", False)
96 118
97 @property 119 @property
98 def main_message(self): 120 def main_message(self):
99 """currently displayed message""" 121 """currently displayed message"""
100 if self.parent.lang in self.message: 122 if self.parent.lang in self.message:
101 self.selected_lang = self.parent.lang 123 self.selected_lang = self.parent.lang
102 return self.message[self.parent.lang] 124 return self.message[self.parent.lang]
103 try: 125 try:
104 self.selected_lang = '' 126 self.selected_lang = ""
105 return self.message[''] 127 return self.message[""]
106 except KeyError: 128 except KeyError:
107 try: 129 try:
108 lang, mess = self.message.iteritems().next() 130 lang, mess = self.message.iteritems().next()
109 self.selected_lang = lang 131 self.selected_lang = lang
110 return mess 132 return mess
111 except StopIteration: 133 except StopIteration:
112 log.error(u"Can't find message for uid {}".format(self.uid)) 134 log.error(u"Can't find message for uid {}".format(self.uid))
113 return '' 135 return ""
114 136
115 @property 137 @property
116 def main_message_xhtml(self): 138 def main_message_xhtml(self):
117 """rich message""" 139 """rich message"""
118 xhtml = {k:v for k,v in self.extra.iteritems() if 'html' in k} 140 xhtml = {k: v for k, v in self.extra.iteritems() if "html" in k}
119 if xhtml: 141 if xhtml:
120 # FIXME: we only return first found value for now 142 # FIXME: we only return first found value for now
121 return next(xhtml.itervalues()) 143 return next(xhtml.itervalues())
122
123 144
124 @property 145 @property
125 def time_text(self): 146 def time_text(self):
126 """Return timestamp in a nicely formatted way""" 147 """Return timestamp in a nicely formatted way"""
127 # if the message was sent before today, we print the full date 148 # if the message was sent before today, we print the full date
128 timestamp = time.localtime(self.timestamp) 149 timestamp = time.localtime(self.timestamp)
129 time_format = u"%c" if timestamp < self.parent.day_change else u"%H:%M" 150 time_format = u"%c" if timestamp < self.parent.day_change else u"%H:%M"
130 return time.strftime(time_format, timestamp).decode(getlocale()[1] or 'utf-8') 151 return time.strftime(time_format, timestamp).decode(getlocale()[1] or "utf-8")
131 152
132 @property 153 @property
133 def avatar(self): 154 def avatar(self):
134 """avatar full path or None if no avatar is found""" 155 """avatar full path or None if no avatar is found"""
135 ret = self.host.getAvatar(self.from_jid, profile=self.profile) 156 ret = self.host.getAvatar(self.from_jid, profile=self.profile)
138 def getNick(self, entity): 159 def getNick(self, entity):
139 """Return nick of an entity when possible""" 160 """Return nick of an entity when possible"""
140 contact_list = self.host.contact_lists[self.profile] 161 contact_list = self.host.contact_lists[self.profile]
141 if self.type == C.MESS_TYPE_INFO and self.info_type in ROOM_USER_MOVED: 162 if self.type == C.MESS_TYPE_INFO and self.info_type in ROOM_USER_MOVED:
142 try: 163 try:
143 return self.extra['user_nick'] 164 return self.extra["user_nick"]
144 except KeyError: 165 except KeyError:
145 log.error(u"extra data is missing user nick for uid {}".format(self.uid)) 166 log.error(u"extra data is missing user nick for uid {}".format(self.uid))
146 return "" 167 return ""
147 # FIXME: converted getSpecials to list for pyjamas 168 # FIXME: converted getSpecials to list for pyjamas
148 if self.parent.type == C.CHAT_GROUP or entity in list(contact_list.getSpecials(C.CONTACT_SPECIAL_GROUP)): 169 if self.parent.type == C.CHAT_GROUP or entity in list(
170 contact_list.getSpecials(C.CONTACT_SPECIAL_GROUP)
171 ):
149 return entity.resource or "" 172 return entity.resource or ""
150 if entity.bare in contact_list: 173 if entity.bare in contact_list:
151 return contact_list.getCache(entity, 'nick') or contact_list.getCache(entity, 'name') or entity.node or entity 174 return (
175 contact_list.getCache(entity, "nick")
176 or contact_list.getCache(entity, "name")
177 or entity.node
178 or entity
179 )
152 return entity.node or entity 180 return entity.node or entity
153 181
154 @property 182 @property
155 def status(self): 183 def status(self):
156 return self._status 184 return self._status
176 else: 204 else:
177 me = False 205 me = False
178 break 206 break
179 if me: 207 if me:
180 self.type = C.MESS_TYPE_INFO 208 self.type = C.MESS_TYPE_INFO
181 self.extra['info_type'] = 'me' 209 self.extra["info_type"] = "me"
182 nick = self.nick 210 nick = self.nick
183 for lang, mess in self.message.iteritems(): 211 for lang, mess in self.message.iteritems():
184 self.message[lang] = u"* " + nick + mess[3:] 212 self.message[lang] = u"* " + nick + mess[3:]
185 213
186 214
188 """Occupant metadata""" 216 """Occupant metadata"""
189 217
190 def __init__(self, parent, data, profile): 218 def __init__(self, parent, data, profile):
191 self.parent = parent 219 self.parent = parent
192 self.profile = profile 220 self.profile = profile
193 self.nick = data['nick'] 221 self.nick = data["nick"]
194 self._entity = data.get('entity') 222 self._entity = data.get("entity")
195 self.affiliation = data['affiliation'] 223 self.affiliation = data["affiliation"]
196 self.role = data['role'] 224 self.role = data["role"]
197 self.widgets = set() # widgets linked to this occupant 225 self.widgets = set() # widgets linked to this occupant
198 self._state = None 226 self._state = None
199 227
200 @property 228 @property
201 def data(self): 229 def data(self):
202 """reconstruct data dict from attributes""" 230 """reconstruct data dict from attributes"""
203 data = {} 231 data = {}
204 data['nick'] = self.nick 232 data["nick"] = self.nick
205 if self._entity is not None: 233 if self._entity is not None:
206 data['entity'] = self._entity 234 data["entity"] = self._entity
207 data['affiliation'] = self.affiliation 235 data["affiliation"] = self.affiliation
208 data['role'] = self.role 236 data["role"] = self.role
209 return data 237 return data
210 238
211 @property 239 @property
212 def jid(self): 240 def jid(self):
213 """jid in the room""" 241 """jid in the room"""
237 for w in self.widgets: 265 for w in self.widgets:
238 w.update(update_dict) 266 w.update(update_dict)
239 267
240 268
241 class QuickChat(quick_widgets.QuickWidget): 269 class QuickChat(quick_widgets.QuickWidget):
242 visible_states = ['chat_state'] # FIXME: to be removed, used only in quick_games 270 visible_states = ["chat_state"] # FIXME: to be removed, used only in quick_games
243 271
244 def __init__(self, host, target, type_=C.CHAT_ONE2ONE, nick=None, occupants=None, subject=None, profiles=None): 272 def __init__(
273 self,
274 host,
275 target,
276 type_=C.CHAT_ONE2ONE,
277 nick=None,
278 occupants=None,
279 subject=None,
280 profiles=None,
281 ):
245 """ 282 """
246 @param type_: can be C.CHAT_ONE2ONE for single conversation or C.CHAT_GROUP for chat à la IRC 283 @param type_: can be C.CHAT_ONE2ONE for single conversation or C.CHAT_GROUP for chat à la IRC
247 """ 284 """
248 self.lang = '' # default language to use for messages 285 self.lang = "" # default language to use for messages
249 quick_widgets.QuickWidget.__init__(self, host, target, profiles=profiles) 286 quick_widgets.QuickWidget.__init__(self, host, target, profiles=profiles)
250 self._locked = True # True when we are waiting for history/search 287 self._locked = True # True when we are waiting for history/search
251 # messageNew signals are cached when locked 288 # messageNew signals are cached when locked
252 self._cache = OrderedDict() 289 self._cache = OrderedDict()
253 assert type_ in (C.CHAT_ONE2ONE, C.CHAT_GROUP) 290 assert type_ in (C.CHAT_ONE2ONE, C.CHAT_GROUP)
254 self.current_target = target 291 self.current_target = target
255 self.type = type_ 292 self.type = type_
256 if type_ == C.CHAT_GROUP: 293 if type_ == C.CHAT_GROUP:
257 if target.resource: 294 if target.resource:
258 raise exceptions.InternalError(u"a group chat entity can't have a resource") 295 raise exceptions.InternalError(
296 u"a group chat entity can't have a resource"
297 )
259 if nick is None: 298 if nick is None:
260 raise exceptions.InternalError(u"nick must not be None for group chat") 299 raise exceptions.InternalError(u"nick must not be None for group chat")
261 300
262 self.nick = nick 301 self.nick = nick
263 self.occupants = {} 302 self.occupants = {}
264 self.setOccupants(occupants) 303 self.setOccupants(occupants)
265 else: 304 else:
266 if occupants is not None or nick is not None: 305 if occupants is not None or nick is not None:
267 raise exceptions.InternalError(u"only group chat can have occupants or nick") 306 raise exceptions.InternalError(
307 u"only group chat can have occupants or nick"
308 )
268 self.messages = OrderedDict() # key: uid, value: Message instance 309 self.messages = OrderedDict() # key: uid, value: Message instance
269 self.games = {} # key=game name (unicode), value=instance of quick_games.RoomGame 310 self.games = {} # key=game name (unicode), value=instance of quick_games.RoomGame
270 self.subject = subject 311 self.subject = subject
271 lt = time.localtime() 312 lt = time.localtime()
272 self.day_change = (lt.tm_year, lt.tm_mon, lt.tm_mday, 0, 0, 0, lt.tm_wday, lt.tm_yday, lt.tm_isdst) # struct_time of day changing time 313 self.day_change = (
314 lt.tm_year,
315 lt.tm_mon,
316 lt.tm_mday,
317 0,
318 0,
319 0,
320 lt.tm_wday,
321 lt.tm_yday,
322 lt.tm_isdst,
323 ) # struct_time of day changing time
273 if self.host.AVATARS_HANDLER: 324 if self.host.AVATARS_HANDLER:
274 self.host.addListener('avatar', self.onAvatar, profiles) 325 self.host.addListener("avatar", self.onAvatar, profiles)
275 326
276 def postInit(self): 327 def postInit(self):
277 """Method to be called by frontend after widget is initialised 328 """Method to be called by frontend after widget is initialised
278 329
279 handle the display of history and subject 330 handle the display of history and subject
282 if self.subject is not None: 333 if self.subject is not None:
283 self.setSubject(self.subject) 334 self.setSubject(self.subject)
284 335
285 def onDelete(self): 336 def onDelete(self):
286 if self.host.AVATARS_HANDLER: 337 if self.host.AVATARS_HANDLER:
287 self.host.removeListener('avatar', self.onAvatar) 338 self.host.removeListener("avatar", self.onAvatar)
288 339
289 @property 340 @property
290 def contact_list(self): 341 def contact_list(self):
291 return self.host.contact_lists[self.profile] 342 return self.host.contact_lists[self.profile]
292 343
293 ## Widget management ## 344 ## Widget management ##
294 345
295 def __str__(self): 346 def __str__(self):
296 return u"Chat Widget [target: {}, type: {}, profile: {}]".format(self.target, self.type, self.profile) 347 return u"Chat Widget [target: {}, type: {}, profile: {}]".format(
348 self.target, self.type, self.profile
349 )
297 350
298 @staticmethod 351 @staticmethod
299 def getWidgetHash(target, profiles): 352 def getWidgetHash(target, profiles):
300 profile = list(profiles)[0] 353 profile = list(profiles)[0]
301 return profile + "\n" + unicode(target.bare) 354 return profile + "\n" + unicode(target.bare)
309 return (unicode(profile), target) 362 return (unicode(profile), target)
310 363
311 def addTarget(self, target): 364 def addTarget(self, target):
312 super(QuickChat, self).addTarget(target) 365 super(QuickChat, self).addTarget(target)
313 if target.resource: 366 if target.resource:
314 self.current_target = target # FIXME: tmp, must use resource priority throught contactList instead 367 self.current_target = (
368 target
369 ) # FIXME: tmp, must use resource priority throught contactList instead
315 370
316 def recreateArgs(self, args, kwargs): 371 def recreateArgs(self, args, kwargs):
317 """copy important attribute for a new widget""" 372 """copy important attribute for a new widget"""
318 kwargs['type_'] = self.type 373 kwargs["type_"] = self.type
319 if self.type == C.CHAT_GROUP: 374 if self.type == C.CHAT_GROUP:
320 kwargs['occupants'] = {o.nick: o.data for o in self.occupants.itervalues()} 375 kwargs["occupants"] = {o.nick: o.data for o in self.occupants.itervalues()}
321 kwargs['subject'] = self.subject 376 kwargs["subject"] = self.subject
322 try: 377 try:
323 kwargs['nick'] = self.nick 378 kwargs["nick"] = self.nick
324 except AttributeError: 379 except AttributeError:
325 pass 380 pass
326 381
327 def onPrivateCreated(self, widget): 382 def onPrivateCreated(self, widget):
328 """Method called when a new widget for private conversation (MUC) is created""" 383 """Method called when a new widget for private conversation (MUC) is created"""
331 def getOrCreatePrivateWidget(self, entity): 386 def getOrCreatePrivateWidget(self, entity):
332 """Create a widget for private conversation, or get it if it already exists 387 """Create a widget for private conversation, or get it if it already exists
333 388
334 @param entity: full jid of the target 389 @param entity: full jid of the target
335 """ 390 """
336 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 391 return self.host.widgets.getOrCreateWidget(
392 QuickChat,
393 entity,
394 type_=C.CHAT_ONE2ONE,
395 force_hash=self.getPrivateHash(self.profile, entity),
396 on_new_widget=self.onPrivateCreated,
397 profile=self.profile,
398 ) # we force hash to have a new widget, not this one again
337 399
338 @property 400 @property
339 def target(self): 401 def target(self):
340 if self.type == C.CHAT_GROUP: 402 if self.type == C.CHAT_GROUP:
341 return self.current_target.bare 403 return self.current_target.bare
345 407
346 def setOccupants(self, occupants): 408 def setOccupants(self, occupants):
347 """set the whole list of occupants""" 409 """set the whole list of occupants"""
348 assert len(self.occupants) == 0 410 assert len(self.occupants) == 0
349 for nick, data in occupants.iteritems(): 411 for nick, data in occupants.iteritems():
350 self.occupants[nick] = Occupant( 412 self.occupants[nick] = Occupant(self, data, self.profile)
351 self,
352 data,
353 self.profile
354 )
355 413
356 def addUser(self, occupant_data): 414 def addUser(self, occupant_data):
357 """Add user if it is not in the group list""" 415 """Add user if it is not in the group list"""
358 occupant = Occupant( 416 occupant = Occupant(self, occupant_data, self.profile)
359 self,
360 occupant_data,
361 self.profile
362 )
363 self.occupants[occupant.nick] = occupant 417 self.occupants[occupant.nick] = occupant
364 return occupant 418 return occupant
365 419
366 def removeUser(self, occupant_data): 420 def removeUser(self, occupant_data):
367 """Remove a user from the group list""" 421 """Remove a user from the group list"""
368 nick = occupant_data['nick'] 422 nick = occupant_data["nick"]
369 try: 423 try:
370 occupant = self.occupants.pop(nick) 424 occupant = self.occupants.pop(nick)
371 except KeyError: 425 except KeyError:
372 log.warning(u"Trying to remove an unknown occupant: {}".format(nick)) 426 log.warning(u"Trying to remove an unknown occupant: {}".format(nick))
373 else: 427 else:
389 @param entity (jid.JID): (full) jid of the sending entity 443 @param entity (jid.JID): (full) jid of the sending entity
390 @param mess_type (str): message type as given by messageNew 444 @param mess_type (str): message type as given by messageNew
391 @return (bool): True if this Chat Widget manage this couple 445 @return (bool): True if this Chat Widget manage this couple
392 """ 446 """
393 if self.type == C.CHAT_GROUP: 447 if self.type == C.CHAT_GROUP:
394 if mess_type in (C.MESS_TYPE_GROUPCHAT, C.MESS_TYPE_INFO) and self.target == entity.bare: 448 if (
449 mess_type in (C.MESS_TYPE_GROUPCHAT, C.MESS_TYPE_INFO)
450 and self.target == entity.bare
451 ):
395 return True 452 return True
396 else: 453 else:
397 if mess_type != C.MESS_TYPE_GROUPCHAT and entity in self.targets: 454 if mess_type != C.MESS_TYPE_GROUPCHAT and entity in self.targets:
398 return True 455 return True
399 return False 456 return False
400 457
401 def updateHistory(self, size=C.HISTORY_LIMIT_DEFAULT, filters=None, profile='@NONE@'): 458 def updateHistory(self, size=C.HISTORY_LIMIT_DEFAULT, filters=None, profile="@NONE@"):
402 """Called when history need to be recreated 459 """Called when history need to be recreated
403 460
404 Remove all message from history then call historyPrint 461 Remove all message from history then call historyPrint
405 Must probably be overriden by frontend to clear widget 462 Must probably be overriden by frontend to clear widget
406 @param size (int): number of messages 463 @param size (int): number of messages
421 self._locked = False 478 self._locked = False
422 for data in self._cache.itervalues(): 479 for data in self._cache.itervalues():
423 self.messageNew(*data) 480 self.messageNew(*data)
424 del self._cache 481 del self._cache
425 482
426 def historyPrint(self, size=C.HISTORY_LIMIT_DEFAULT, filters=None, profile='@NONE@'): 483 def historyPrint(self, size=C.HISTORY_LIMIT_DEFAULT, filters=None, profile="@NONE@"):
427 """Print the current history 484 """Print the current history
428 485
429 @param size (int): number of messages 486 @param size (int): number of messages
430 @param search (str): pattern to filter the history results 487 @param search (str): pattern to filter the history results
431 @param profile (str): %(doc_profile)s 488 @param profile (str): %(doc_profile)s
440 if size != C.HISTORY_LIMIT_DEFAULT: 497 if size != C.HISTORY_LIMIT_DEFAULT:
441 log_msg += _(u" ({} messages)".format(size)) 498 log_msg += _(u" ({} messages)".format(size))
442 log.debug(log_msg) 499 log.debug(log_msg)
443 500
444 if self.type == C.CHAT_ONE2ONE: 501 if self.type == C.CHAT_ONE2ONE:
445 special = self.host.contact_lists[self.profile].getCache(self.target, C.CONTACT_SPECIAL) 502 special = self.host.contact_lists[self.profile].getCache(
503 self.target, C.CONTACT_SPECIAL
504 )
446 if special == C.CONTACT_SPECIAL_GROUP: 505 if special == C.CONTACT_SPECIAL_GROUP:
447 # we have a private conversation 506 # we have a private conversation
448 # so we need full jid for the history 507 # so we need full jid for the history
449 # (else we would get history from group itself) 508 # (else we would get history from group itself)
450 # and to filter out groupchat message 509 # and to filter out groupchat message
451 target = self.target 510 target = self.target
452 filters['not_types'] = C.MESS_TYPE_GROUPCHAT 511 filters["not_types"] = C.MESS_TYPE_GROUPCHAT
453 else: 512 else:
454 target = self.target.bare 513 target = self.target.bare
455 else: 514 else:
456 # groupchat 515 # groupchat
457 target = self.target.bare 516 target = self.target.bare
458 # FIXME: info not handled correctly 517 # FIXME: info not handled correctly
459 filters['types'] = C.MESS_TYPE_GROUPCHAT 518 filters["types"] = C.MESS_TYPE_GROUPCHAT
460 519
461 def _historyGetCb(history): 520 def _historyGetCb(history):
462 # day_format = "%A, %d %b %Y" # to display the day change 521 # day_format = "%A, %d %b %Y" # to display the day change
463 # previous_day = datetime.now().strftime(day_format) 522 # previous_day = datetime.now().strftime(day_format)
464 # message_day = datetime.fromtimestamp(timestamp).strftime(self.day_format) 523 # message_day = datetime.fromtimestamp(timestamp).strftime(self.day_format)
474 from_jid = jid.JID(from_jid) 533 from_jid = jid.JID(from_jid)
475 to_jid = jid.JID(to_jid) 534 to_jid = jid.JID(to_jid)
476 # if ((self.type == C.CHAT_GROUP and type_ != C.MESS_TYPE_GROUPCHAT) or 535 # if ((self.type == C.CHAT_GROUP and type_ != C.MESS_TYPE_GROUPCHAT) or
477 # (self.type == C.CHAT_ONE2ONE and type_ == C.MESS_TYPE_GROUPCHAT)): 536 # (self.type == C.CHAT_ONE2ONE and type_ == C.MESS_TYPE_GROUPCHAT)):
478 # continue 537 # continue
479 extra['history'] = True 538 extra["history"] = True
480 self.messages[uid] = Message(self, uid, timestamp, from_jid, to_jid, message, subject, type_, extra, profile) 539 self.messages[uid] = Message(
540 self,
541 uid,
542 timestamp,
543 from_jid,
544 to_jid,
545 message,
546 subject,
547 type_,
548 extra,
549 profile,
550 )
481 self._onHistoryPrinted() 551 self._onHistoryPrinted()
482 552
483 def _historyGetEb(err): 553 def _historyGetEb(err):
484 log.error(_(u"Can't get history: {}").format(err)) 554 log.error(_(u"Can't get history: {}").format(err))
485 self._onHistoryPrinted() 555 self._onHistoryPrinted()
486 556
487 self.host.bridge.historyGet(unicode(self.host.profiles[profile].whoami.bare), unicode(target), size, True, filters, profile, callback=_historyGetCb, errback=_historyGetEb) 557 self.host.bridge.historyGet(
488 558 unicode(self.host.profiles[profile].whoami.bare),
489 def messageNew(self, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile): 559 unicode(target),
560 size,
561 True,
562 filters,
563 profile,
564 callback=_historyGetCb,
565 errback=_historyGetEb,
566 )
567
568 def messageNew(
569 self, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile
570 ):
490 if self._locked: 571 if self._locked:
491 self._cache[uid] = (uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile) 572 self._cache[uid] = (
573 uid,
574 timestamp,
575 from_jid,
576 to_jid,
577 msg,
578 subject,
579 type_,
580 extra,
581 profile,
582 )
492 return 583 return
493 if self.type == C.CHAT_GROUP: 584 if self.type == C.CHAT_GROUP:
494 if to_jid.resource and type_ != C.MESS_TYPE_GROUPCHAT: 585 if to_jid.resource and type_ != C.MESS_TYPE_GROUPCHAT:
495 # we have a private message, we forward it to a private conversation widget 586 # we have a private message, we forward it to a private conversation widget
496 chat_widget = self.getOrCreatePrivateWidget(to_jid) 587 chat_widget = self.getOrCreatePrivateWidget(to_jid)
497 chat_widget.messageNew(uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile) 588 chat_widget.messageNew(
589 uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile
590 )
498 return 591 return
499 if type_ == C.MESS_TYPE_INFO: 592 if type_ == C.MESS_TYPE_INFO:
500 try: 593 try:
501 info_type = extra['info_type'] 594 info_type = extra["info_type"]
502 except KeyError: 595 except KeyError:
503 pass 596 pass
504 else: 597 else:
505 user_data = {k[5:]:v for k,v in extra.iteritems() if k.startswith('user_')} 598 user_data = {
599 k[5:]: v for k, v in extra.iteritems() if k.startswith("user_")
600 }
506 if info_type == ROOM_USER_JOINED: 601 if info_type == ROOM_USER_JOINED:
507 self.addUser(user_data) 602 self.addUser(user_data)
508 elif info_type == ROOM_USER_LEFT: 603 elif info_type == ROOM_USER_LEFT:
509 self.removeUser(user_data) 604 self.removeUser(user_data)
510 605
511 message = Message(self, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile) 606 message = Message(
607 self, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile
608 )
512 self.messages[uid] = message 609 self.messages[uid] = message
513 610
514 if 'received_timestamp' in extra: 611 if "received_timestamp" in extra:
515 log.warning(u"Delayed message received after history, this should not happen") 612 log.warning(u"Delayed message received after history, this should not happen")
516 self.createMessage(message) 613 self.createMessage(message)
517 614
518 def createMessage(self, message, append=False): 615 def createMessage(self, message, append=False):
519 """Must be implemented by frontend to create and show a new message widget 616 """Must be implemented by frontend to create and show a new message widget
535 ## Room ## 632 ## Room ##
536 633
537 def setSubject(self, subject): 634 def setSubject(self, subject):
538 """Set title for a group chat""" 635 """Set title for a group chat"""
539 if self.type != C.CHAT_GROUP: 636 if self.type != C.CHAT_GROUP:
540 raise exceptions.InternalError("trying to set subject for a non group chat window") 637 raise exceptions.InternalError(
638 "trying to set subject for a non group chat window"
639 )
541 self.subject = subject 640 self.subject = subject
542 641
543 def changeSubject(self, new_subject): 642 def changeSubject(self, new_subject):
544 """Change the subject of the room 643 """Change the subject of the room
545 644
577 if self.type == C.CHAT_GROUP: 676 if self.type == C.CHAT_GROUP:
578 nick = from_jid.resource 677 nick = from_jid.resource
579 try: 678 try:
580 self.occupants[nick].state = state 679 self.occupants[nick].state = state
581 except KeyError: 680 except KeyError:
582 log.warning(u"{nick} not found in {room}, ignoring new chat state".format( 681 log.warning(
583 nick=nick, room=self.target.bare)) 682 u"{nick} not found in {room}, ignoring new chat state".format(
683 nick=nick, room=self.target.bare
684 )
685 )
584 686
585 def onMessageState(self, uid, status, profile): 687 def onMessageState(self, uid, status, profile):
586 try: 688 try:
587 mess_data = self.messages[uid] 689 mess_data = self.messages[uid]
588 except KeyError: 690 except KeyError:
592 694
593 def onAvatar(self, entity, filename, profile): 695 def onAvatar(self, entity, filename, profile):
594 if self.type == C.CHAT_GROUP: 696 if self.type == C.CHAT_GROUP:
595 if entity.bare == self.target: 697 if entity.bare == self.target:
596 try: 698 try:
597 self.occupants[entity.resource].update({'avatar': filename}) 699 self.occupants[entity.resource].update({"avatar": filename})
598 except KeyError: 700 except KeyError:
599 # can happen for a message in history where the 701 # can happen for a message in history where the
600 # entity is not here anymore 702 # entity is not here anymore
601 pass 703 pass
602 704
603 for m in self.messages.values(): 705 for m in self.messages.values():
604 if m.nick == entity.resource: 706 if m.nick == entity.resource:
605 for w in m.widgets: 707 for w in m.widgets:
606 w.update({'avatar': filename}) 708 w.update({"avatar": filename})
607 else: 709 else:
608 if entity.bare == self.target.bare or entity.bare == self.host.profiles[profile].whoami.bare: 710 if (
711 entity.bare == self.target.bare
712 or entity.bare == self.host.profiles[profile].whoami.bare
713 ):
609 log.info(u"avatar updated for {}".format(entity)) 714 log.info(u"avatar updated for {}".format(entity))
610 for m in self.messages.values(): 715 for m in self.messages.values():
611 if m.from_jid.bare == entity.bare: 716 if m.from_jid.bare == entity.bare:
612 for w in m.widgets: 717 for w in m.widgets:
613 w.update({'avatar': filename}) 718 w.update({"avatar": filename})
614 719
615 720
616 quick_widgets.register(QuickChat) 721 quick_widgets.register(QuickChat)