Mercurial > libervia-backend
comparison libervia/backend/plugins/plugin_xep_0054.py @ 4270:0d7bb4df2343
Reformatted code base using black.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 19 Jun 2024 18:44:57 +0200 |
parents | 4b842c1fb686 |
children |
comparison
equal
deleted
inserted
replaced
4269:64a85ce8be70 | 4270:0d7bb4df2343 |
---|---|
76 class XEP_0054(object): | 76 class XEP_0054(object): |
77 | 77 |
78 def __init__(self, host): | 78 def __init__(self, host): |
79 log.info(_("Plugin XEP_0054 initialization")) | 79 log.info(_("Plugin XEP_0054 initialization")) |
80 self.host = host | 80 self.host = host |
81 self._i = host.plugins['IDENTITY'] | 81 self._i = host.plugins["IDENTITY"] |
82 self._i.register(IMPORT_NAME, 'avatar', self.get_avatar, self.set_avatar) | 82 self._i.register(IMPORT_NAME, "avatar", self.get_avatar, self.set_avatar) |
83 self._i.register(IMPORT_NAME, 'nicknames', self.get_nicknames, self.set_nicknames) | 83 self._i.register(IMPORT_NAME, "nicknames", self.get_nicknames, self.set_nicknames) |
84 host.trigger.add("presence_available", self.presence_available_trigger) | 84 host.trigger.add("presence_available", self.presence_available_trigger) |
85 | 85 |
86 def get_handler(self, client): | 86 def get_handler(self, client): |
87 return XEP_0054_handler(self) | 87 return XEP_0054_handler(self) |
88 | 88 |
89 def presence_available_trigger(self, presence_elt, client): | 89 def presence_available_trigger(self, presence_elt, client): |
90 try: | 90 try: |
91 avatar_hash = client._xep_0054_avatar_hashes[client.jid.userhost()] | 91 avatar_hash = client._xep_0054_avatar_hashes[client.jid.userhost()] |
92 except KeyError: | 92 except KeyError: |
93 log.info( | 93 log.info(_("No avatar in cache for {profile}").format(profile=client.profile)) |
94 _("No avatar in cache for {profile}") | |
95 .format(profile=client.profile)) | |
96 return True | 94 return True |
97 x_elt = domish.Element((NS_VCARD_UPDATE, "x")) | 95 x_elt = domish.Element((NS_VCARD_UPDATE, "x")) |
98 x_elt.addElement("photo", content=avatar_hash) | 96 x_elt.addElement("photo", content=avatar_hash) |
99 presence_elt.addChild(x_elt) | 97 presence_elt.addChild(x_elt) |
100 return True | 98 return True |
101 | 99 |
102 async def profile_connecting(self, client): | 100 async def profile_connecting(self, client): |
103 client._xep_0054_avatar_hashes = persistent.PersistentDict( | 101 client._xep_0054_avatar_hashes = persistent.PersistentDict( |
104 NS_VCARD, client.profile) | 102 NS_VCARD, client.profile |
103 ) | |
105 await client._xep_0054_avatar_hashes.load() | 104 await client._xep_0054_avatar_hashes.load() |
106 | 105 |
107 def save_photo(self, client, photo_elt, entity): | 106 def save_photo(self, client, photo_elt, entity): |
108 """Parse a <PHOTO> photo_elt and save the picture""" | 107 """Parse a <PHOTO> photo_elt and save the picture""" |
109 # XXX: this method is launched in a separate thread | 108 # XXX: this method is launched in a separate thread |
134 del buf | 133 del buf |
135 | 134 |
136 if mime_type is None: | 135 if mime_type is None: |
137 log.debug( | 136 log.debug( |
138 f"no media type found specified for {entity}'s avatar, trying to " | 137 f"no media type found specified for {entity}'s avatar, trying to " |
139 f"guess") | 138 f"guess" |
139 ) | |
140 | 140 |
141 try: | 141 try: |
142 mime_type = image.guess_type(io.BytesIO(decoded)) | 142 mime_type = image.guess_type(io.BytesIO(decoded)) |
143 except IOError as e: | 143 except IOError as e: |
144 log.warning(f"Can't open avatar buffer: {e}") | 144 log.warning(f"Can't open avatar buffer: {e}") |
166 if elem.name == "FN": | 166 if elem.name == "FN": |
167 vcard_dict["fullname"] = str(elem) | 167 vcard_dict["fullname"] = str(elem) |
168 elif elem.name == "NICKNAME": | 168 elif elem.name == "NICKNAME": |
169 nickname = vcard_dict["nickname"] = str(elem) | 169 nickname = vcard_dict["nickname"] = str(elem) |
170 await self._i.update( | 170 await self._i.update( |
171 client, | 171 client, IMPORT_NAME, "nicknames", [nickname], entity_jid |
172 IMPORT_NAME, | |
173 "nicknames", | |
174 [nickname], | |
175 entity_jid | |
176 ) | 172 ) |
177 elif elem.name == "URL": | 173 elif elem.name == "URL": |
178 vcard_dict["website"] = str(elem) | 174 vcard_dict["website"] = str(elem) |
179 elif elem.name == "EMAIL": | 175 elif elem.name == "EMAIL": |
180 vcard_dict["email"] = str(elem) | 176 vcard_dict["email"] = str(elem) |
194 avatar_hash = None | 190 avatar_hash = None |
195 else: | 191 else: |
196 vcard_dict["avatar"] = avatar_hash | 192 vcard_dict["avatar"] = avatar_hash |
197 if avatar_hash is not None: | 193 if avatar_hash is not None: |
198 await client._xep_0054_avatar_hashes.aset( | 194 await client._xep_0054_avatar_hashes.aset( |
199 entity_jid.full(), avatar_hash) | 195 entity_jid.full(), avatar_hash |
196 ) | |
200 | 197 |
201 if avatar_hash: | 198 if avatar_hash: |
202 avatar_cache = self.host.common_cache.get_metadata(avatar_hash) | 199 avatar_cache = self.host.common_cache.get_metadata(avatar_hash) |
203 await self._i.update( | 200 await self._i.update( |
204 client, | 201 client, |
205 IMPORT_NAME, | 202 IMPORT_NAME, |
206 "avatar", | 203 "avatar", |
207 { | 204 { |
208 'path': avatar_cache['path'], | 205 "path": avatar_cache["path"], |
209 'filename': avatar_cache['filename'], | 206 "filename": avatar_cache["filename"], |
210 'media_type': avatar_cache['mime_type'], | 207 "media_type": avatar_cache["mime_type"], |
211 'cache_uid': avatar_hash | 208 "cache_uid": avatar_hash, |
212 }, | 209 }, |
213 entity_jid | 210 entity_jid, |
214 ) | 211 ) |
215 else: | 212 else: |
216 await self._i.update( | 213 await self._i.update( |
217 client, IMPORT_NAME, "avatar", None, entity_jid) | 214 client, IMPORT_NAME, "avatar", None, entity_jid |
215 ) | |
218 else: | 216 else: |
219 log.debug("FIXME: [{}] VCard_elt tag is not managed yet".format(elem.name)) | 217 log.debug( |
218 "FIXME: [{}] VCard_elt tag is not managed yet".format(elem.name) | |
219 ) | |
220 | 220 |
221 return vcard_dict | 221 return vcard_dict |
222 | 222 |
223 async def get_vcard_element(self, client, entity_jid): | 223 async def get_vcard_element(self, client, entity_jid): |
224 """Retrieve domish.Element of a VCard | 224 """Retrieve domish.Element of a VCard |
232 iq_elt.addElement("vCard", NS_VCARD) | 232 iq_elt.addElement("vCard", NS_VCARD) |
233 iq_ret_elt = await iq_elt.send(entity_jid.full()) | 233 iq_ret_elt = await iq_elt.send(entity_jid.full()) |
234 try: | 234 try: |
235 return next(iq_ret_elt.elements(NS_VCARD, "vCard")) | 235 return next(iq_ret_elt.elements(NS_VCARD, "vCard")) |
236 except StopIteration: | 236 except StopIteration: |
237 log.warning(_( | 237 log.warning( |
238 "vCard element not found for {entity_jid}: {xml}" | 238 _("vCard element not found for {entity_jid}: {xml}").format( |
239 ).format(entity_jid=entity_jid, xml=iq_ret_elt.toXml())) | 239 entity_jid=entity_jid, xml=iq_ret_elt.toXml() |
240 ) | |
241 ) | |
240 raise exceptions.DataError(f"no vCard element found for {entity_jid}") | 242 raise exceptions.DataError(f"no vCard element found for {entity_jid}") |
241 | 243 |
242 async def update_vcard_elt(self, client, entity_jid, to_replace): | 244 async def update_vcard_elt(self, client, entity_jid, to_replace): |
243 """Create a vcard element to replace some metadata | 245 """Create a vcard element to replace some metadata |
244 | 246 |
277 try: | 279 try: |
278 vcard_elt = await self.get_vcard_element(client, entity_jid) | 280 vcard_elt = await self.get_vcard_element(client, entity_jid) |
279 except exceptions.DataError: | 281 except exceptions.DataError: |
280 self._i.update(client, IMPORT_NAME, "avatar", None, entity_jid) | 282 self._i.update(client, IMPORT_NAME, "avatar", None, entity_jid) |
281 except Exception as e: | 283 except Exception as e: |
282 log.warning(_( | 284 log.warning( |
283 "Can't get vCard for {entity_jid}: {e}" | 285 _("Can't get vCard for {entity_jid}: {e}").format( |
284 ).format(entity_jid=entity_jid, e=e)) | 286 entity_jid=entity_jid, e=e |
287 ) | |
288 ) | |
285 else: | 289 else: |
286 log.debug(_("VCard found")) | 290 log.debug(_("VCard found")) |
287 return await self.v_card_2_dict(client, vcard_elt, entity_jid) | 291 return await self.v_card_2_dict(client, vcard_elt, entity_jid) |
288 | 292 |
289 async def get_avatar( | 293 async def get_avatar( |
290 self, | 294 self, client: SatXMPPEntity, entity_jid: jid.JID |
291 client: SatXMPPEntity, | 295 ) -> Optional[dict]: |
292 entity_jid: jid.JID | |
293 ) -> Optional[dict]: | |
294 """Get avatar data | 296 """Get avatar data |
295 | 297 |
296 @param entity: entity to get avatar from | 298 @param entity: entity to get avatar from |
297 @return: avatar metadata, or None if no avatar has been found | 299 @return: avatar metadata, or None if no avatar has been found |
298 """ | 300 """ |
302 if vcard is None: | 304 if vcard is None: |
303 return None | 305 return None |
304 try: | 306 try: |
305 avatar_hash = hashes_cache[entity_jid.full()] | 307 avatar_hash = hashes_cache[entity_jid.full()] |
306 except KeyError: | 308 except KeyError: |
307 if 'avatar' in vcard: | 309 if "avatar" in vcard: |
308 raise exceptions.InternalError( | 310 raise exceptions.InternalError( |
309 "No avatar hash while avatar is found in vcard") | 311 "No avatar hash while avatar is found in vcard" |
312 ) | |
310 return None | 313 return None |
311 | 314 |
312 if not avatar_hash: | 315 if not avatar_hash: |
313 return None | 316 return None |
314 | 317 |
315 avatar_cache = self.host.common_cache.get_metadata(avatar_hash) | 318 avatar_cache = self.host.common_cache.get_metadata(avatar_hash) |
316 return self._i.avatar_build_metadata( | 319 return self._i.avatar_build_metadata( |
317 avatar_cache['path'], avatar_cache['mime_type'], avatar_hash) | 320 avatar_cache["path"], avatar_cache["mime_type"], avatar_hash |
321 ) | |
318 | 322 |
319 async def set_avatar(self, client, avatar_data, entity): | 323 async def set_avatar(self, client, avatar_data, entity): |
320 """Set avatar of the profile | 324 """Set avatar of the profile |
321 | 325 |
322 @param avatar_data(dict): data of the image to use as avatar, as built by | 326 @param avatar_data(dict): data of the image to use as avatar, as built by |
323 IDENTITY plugin. | 327 IDENTITY plugin. |
324 @param entity(jid.JID): entity whose avatar must be changed | 328 @param entity(jid.JID): entity whose avatar must be changed |
325 """ | 329 """ |
326 vcard_elt = await self.update_vcard_elt(client, entity, ['PHOTO']) | 330 vcard_elt = await self.update_vcard_elt(client, entity, ["PHOTO"]) |
327 | 331 |
328 iq_elt = client.IQ() | 332 iq_elt = client.IQ() |
329 iq_elt.addChild(vcard_elt) | 333 iq_elt.addChild(vcard_elt) |
330 # metadata with encoded image are now filled at the right size/format | 334 # metadata with encoded image are now filled at the right size/format |
331 photo_elt = vcard_elt.addElement("PHOTO") | 335 photo_elt = vcard_elt.addElement("PHOTO") |
343 @param entity(jid.JID): entity to get nick from | 347 @param entity(jid.JID): entity to get nick from |
344 @return(list[str]): nicknames found | 348 @return(list[str]): nicknames found |
345 """ | 349 """ |
346 vcard_data = await self.get_card(client, entity) | 350 vcard_data = await self.get_card(client, entity) |
347 try: | 351 try: |
348 return [vcard_data['nickname']] | 352 return [vcard_data["nickname"]] |
349 except (KeyError, TypeError): | 353 except (KeyError, TypeError): |
350 return [] | 354 return [] |
351 | 355 |
352 async def set_nicknames(self, client, nicknames, entity): | 356 async def set_nicknames(self, client, nicknames, entity): |
353 """Update our vCard and set a nickname | 357 """Update our vCard and set a nickname |
355 @param nicknames(list[str]): new nicknames to use | 359 @param nicknames(list[str]): new nicknames to use |
356 only first item of this list will be used here | 360 only first item of this list will be used here |
357 """ | 361 """ |
358 nick = nicknames[0].strip() | 362 nick = nicknames[0].strip() |
359 | 363 |
360 vcard_elt = await self.update_vcard_elt(client, entity, ['NICKNAME']) | 364 vcard_elt = await self.update_vcard_elt(client, entity, ["NICKNAME"]) |
361 | 365 |
362 if nick: | 366 if nick: |
363 vcard_elt.addElement((NS_VCARD, "NICKNAME"), content=nick) | 367 vcard_elt.addElement((NS_VCARD, "NICKNAME"), content=nick) |
364 iq_elt = client.IQ() | 368 iq_elt = client.IQ() |
365 iq_elt.addChild(vcard_elt) | 369 iq_elt.addChild(vcard_elt) |
388 Check for avatar information, and get VCard if needed | 392 Check for avatar information, and get VCard if needed |
389 @param presence(domish.Element): <presence/> stanza | 393 @param presence(domish.Element): <presence/> stanza |
390 """ | 394 """ |
391 client = self.parent | 395 client = self.parent |
392 entity_jid = self.plugin_parent._i.get_identity_jid( | 396 entity_jid = self.plugin_parent._i.get_identity_jid( |
393 client, jid.JID(presence["from"])) | 397 client, jid.JID(presence["from"]) |
398 ) | |
394 | 399 |
395 try: | 400 try: |
396 x_elt = next(presence.elements(NS_VCARD_UPDATE, "x")) | 401 x_elt = next(presence.elements(NS_VCARD_UPDATE, "x")) |
397 except StopIteration: | 402 except StopIteration: |
398 return | 403 return |
432 | 437 |
433 await hashes_cache.aset(entity_jid.full(), given_hash) | 438 await hashes_cache.aset(entity_jid.full(), given_hash) |
434 | 439 |
435 if not given_hash: | 440 if not given_hash: |
436 await self.plugin_parent._i.update( | 441 await self.plugin_parent._i.update( |
437 client, IMPORT_NAME, "avatar", None, entity_jid) | 442 client, IMPORT_NAME, "avatar", None, entity_jid |
443 ) | |
438 # the avatar has been removed, no need to go further | 444 # the avatar has been removed, no need to go further |
439 return | 445 return |
440 | 446 |
441 avatar_cache = self.host.common_cache.get_metadata(given_hash) | 447 avatar_cache = self.host.common_cache.get_metadata(given_hash) |
442 if avatar_cache is not None: | 448 if avatar_cache is not None: |
443 log.debug( | 449 log.debug( |
444 f"New avatar found for [{entity_jid}], it's already in cache, we use it" | 450 f"New avatar found for [{entity_jid}], it's already in cache, we use it" |
445 ) | 451 ) |
446 await self.plugin_parent._i.update( | 452 await self.plugin_parent._i.update( |
447 client, | 453 client, |
448 IMPORT_NAME, "avatar", | 454 IMPORT_NAME, |
455 "avatar", | |
449 { | 456 { |
450 'path': avatar_cache['path'], | 457 "path": avatar_cache["path"], |
451 'filename': avatar_cache['filename'], | 458 "filename": avatar_cache["filename"], |
452 'media_type': avatar_cache['mime_type'], | 459 "media_type": avatar_cache["mime_type"], |
453 'cache_uid': given_hash, | 460 "cache_uid": given_hash, |
454 }, | 461 }, |
455 entity_jid | 462 entity_jid, |
456 ) | 463 ) |
457 else: | 464 else: |
458 log.debug( | 465 log.debug("New avatar found for [{entity_jid}], requesting vcard") |
459 "New avatar found for [{entity_jid}], requesting vcard" | |
460 ) | |
461 vcard = await self.plugin_parent.get_card(client, entity_jid) | 466 vcard = await self.plugin_parent.get_card(client, entity_jid) |
462 if vcard is None: | 467 if vcard is None: |
463 log.warning(f"Unexpected empty vCard for {entity_jid}") | 468 log.warning(f"Unexpected empty vCard for {entity_jid}") |
464 return | 469 return |
465 computed_hash = client._xep_0054_avatar_hashes[entity_jid.full()] | 470 computed_hash = client._xep_0054_avatar_hashes[entity_jid.full()] |