comparison sat/plugins/plugin_misc_identity.py @ 3817:998c5318230f

plugin identity: make the plugin compatible with component + description: the plugin can now be used with components. the new `description` field is now available. rel 368
author Goffi <goffi@goffi.org>
date Wed, 29 Jun 2022 11:49:03 +0200
parents 213e83a4ed10
children 524856bd7b19
comparison
equal deleted inserted replaced
3816:213e83a4ed10 3817:998c5318230f
52 52
53 PLUGIN_INFO = { 53 PLUGIN_INFO = {
54 C.PI_NAME: "Identity Plugin", 54 C.PI_NAME: "Identity Plugin",
55 C.PI_IMPORT_NAME: IMPORT_NAME, 55 C.PI_IMPORT_NAME: IMPORT_NAME,
56 C.PI_TYPE: C.PLUG_TYPE_MISC, 56 C.PI_TYPE: C.PLUG_TYPE_MISC,
57 C.PI_MODES: C.PLUG_MODE_BOTH,
57 C.PI_PROTOCOLS: [], 58 C.PI_PROTOCOLS: [],
58 C.PI_DEPENDENCIES: [], 59 C.PI_DEPENDENCIES: [],
59 C.PI_RECOMMENDATIONS: ["XEP-0045"], 60 C.PI_RECOMMENDATIONS: ["XEP-0045"],
60 C.PI_MAIN: "Identity", 61 C.PI_MAIN: "Identity",
61 C.PI_HANDLER: "no", 62 C.PI_HANDLER: "no",
93 # append nicknames from roster, resource, etc. 94 # append nicknames from roster, resource, etc.
94 "get_post_treatment": self.nicknamesGetPostTreatment, 95 "get_post_treatment": self.nicknamesGetPostTreatment,
95 "update_is_new_data": self.nicknamesUpdateIsNewData, 96 "update_is_new_data": self.nicknamesUpdateIsNewData,
96 "store": True, 97 "store": True,
97 }, 98 },
99 "description": {
100 "type": str,
101 "get_all": True,
102 "get_post_treatment": self.descriptionGetPostTreatment,
103 "store": True,
104 }
98 } 105 }
99 host.trigger.add("roster_update", self._rosterUpdateTrigger) 106 host.trigger.add("roster_update", self._rosterUpdateTrigger)
100 host.memory.setSignalOnUpdate("avatar") 107 host.memory.setSignalOnUpdate("avatar")
101 host.memory.setSignalOnUpdate("nicknames") 108 host.memory.setSignalOnUpdate("nicknames")
102 host.bridge.addMethod( 109 host.bridge.addMethod(
261 if not isinstance(value, value_type): 268 if not isinstance(value, value_type):
262 raise ValueError( 269 raise ValueError(
263 f"{value} has wrong type: it is {type(value)} while {value_type} was " 270 f"{value} has wrong type: it is {type(value)} while {value_type} was "
264 f"expected") 271 f"expected")
265 272
273 def getFieldType(self, metadata_name: str) -> str:
274 """Return the type the requested field
275
276 @param metadata_name: name of the field to check
277 @raise KeyError: the request field doesn't exist
278 """
279 return self.metadata[metadata_name]["type"]
280
266 async def get( 281 async def get(
267 self, 282 self,
268 client: SatXMPPEntity, 283 client: SatXMPPEntity,
269 metadata_name: str, 284 metadata_name: str,
270 entity: Optional[jid.JID], 285 entity: Optional[jid.JID],
328 .format(callback=callback.get, metadata_name=metadata_name, e=e)) 343 .format(callback=callback.get, metadata_name=metadata_name, e=e))
329 else: 344 else:
330 if data: 345 if data:
331 self.checkType(metadata_name, data) 346 self.checkType(metadata_name, data)
332 if get_all: 347 if get_all:
333 all_data.extend(data) 348 if isinstance(data, list):
349 all_data.extend(data)
350 else:
351 all_data.append(data)
334 else: 352 else:
335 break 353 break
336 else: 354 else:
337 data = None 355 data = None
338 356
394 post_treatment = metadata.get("set_post_treatment") 412 post_treatment = metadata.get("set_post_treatment")
395 if post_treatment is not None: 413 if post_treatment is not None:
396 await utils.asDeferred(post_treatment, client, entity, data) 414 await utils.asDeferred(post_treatment, client, entity, data)
397 415
398 async def update( 416 async def update(
399 self, 417 self,
400 client: SatXMPPEntity, 418 client: SatXMPPEntity,
401 origin: str, 419 origin: str,
402 metadata_name: str, 420 metadata_name: str,
403 data: Any, 421 data: Any,
404 entity: Optional[jid.JID] 422 entity: Optional[jid.JID]
405 ): 423 ):
406 """Update a metadata in cache 424 """Update a metadata in cache
407 425
408 This method may be called by plugins when an identity metadata is available. 426 This method may be called by plugins when an identity metadata is available.
409 @param origin: namespace of the plugin which is source of the metadata 427 @param origin: namespace of the plugin which is source of the metadata
410 """ 428 """
624 - roster, plugins set nicknames 642 - roster, plugins set nicknames
625 - if no nickname is found, user part of jid is then used, or bare jid 643 - if no nickname is found, user part of jid is then used, or bare jid
626 if there is no user part. 644 if there is no user part.
627 For MUC, room nick is always put first 645 For MUC, room nick is always put first
628 """ 646 """
629 # we first check roster
630 nicknames = [] 647 nicknames = []
648
649 # for MUC we add resource
631 if entity.resource: 650 if entity.resource:
632 # getIdentityJid let the resource only if the entity is a MUC room 651 # getIdentityJid let the resource only if the entity is a MUC room
633 # occupant jid 652 # occupant jid
634 nicknames.append(entity.resource) 653 nicknames.append(entity.resource)
635 654
636 roster_item = client.roster.getItem(entity.userhostJID()) 655 # we first check roster (if we are not in a component)
637 if roster_item is not None and roster_item.name: 656 if not client.is_component:
638 # user set name has priority over entity set name 657 roster_item = client.roster.getItem(entity.userhostJID())
639 nicknames.append(roster_item.name) 658 if roster_item is not None and roster_item.name:
659 # user set name has priority over entity set name
660 nicknames.append(roster_item.name)
640 661
641 nicknames.extend(plugin_nicknames) 662 nicknames.extend(plugin_nicknames)
642 663
643 if not nicknames: 664 if not nicknames:
644 if entity.user: 665 if entity.user:
649 # we remove duplicates while preserving order with dict 670 # we remove duplicates while preserving order with dict
650 return list(dict.fromkeys(nicknames)) 671 return list(dict.fromkeys(nicknames))
651 672
652 def nicknamesUpdateIsNewData(self, client, entity, cached_data, new_nicknames): 673 def nicknamesUpdateIsNewData(self, client, entity, cached_data, new_nicknames):
653 return not set(new_nicknames).issubset(cached_data) 674 return not set(new_nicknames).issubset(cached_data)
675
676 async def descriptionGetPostTreatment(
677 self,
678 client: SatXMPPEntity,
679 entity: jid.JID,
680 plugin_description: List[str]
681 ) -> str:
682 """Join all descriptions in a unique string"""
683 return '\n'.join(plugin_description)
654 684
655 def _getIdentity(self, entity_s, metadata_filter, use_cache, profile): 685 def _getIdentity(self, entity_s, metadata_filter, use_cache, profile):
656 entity = jid.JID(entity_s) 686 entity = jid.JID(entity_s)
657 client = self.host.getClient(profile) 687 client = self.host.getClient(profile)
658 d = defer.ensureDeferred( 688 d = defer.ensureDeferred(
659 self.getIdentity(client, entity, metadata_filter, use_cache)) 689 self.getIdentity(client, entity, metadata_filter, use_cache))
660 d.addCallback(data_format.serialise) 690 d.addCallback(data_format.serialise)
661 return d 691 return d
662 692
663 async def getIdentity( 693 async def getIdentity(
664 self, client, entity=None, metadata_filter=None, use_cache=True): 694 self,
695 client: SatXMPPEntity,
696 entity: Optional[jid.JID] = None,
697 metadata_filter: Optional[List[str]] = None,
698 use_cache: bool = True
699 ) -> Dict[str, Any]:
665 """Retrieve identity of an entity 700 """Retrieve identity of an entity
666 701
667 @param entity(jid.JID, None): entity to check 702 @param entity: entity to check
668 @param metadata_filter(list[str], None): if not None or empty, only return 703 @param metadata_filter: if not None or empty, only return
669 metadata in this filter 704 metadata in this filter
670 @param use_cache(bool): if False, cache won't be checked 705 @param use_cache: if False, cache won't be checked
671 should be True most of time, to avoid useless network requests 706 should be True most of time, to avoid useless network requests
672 @return (dict): identity data 707 @return: identity data
673 """ 708 """
674 id_data = {} 709 id_data = {}
675 710
676 if not metadata_filter: 711 if not metadata_filter:
677 metadata_names = self.metadata.keys() 712 metadata_names = self.metadata.keys()
739 """Retrieve identities for entities in roster + own identity + invitations 774 """Retrieve identities for entities in roster + own identity + invitations
740 775
741 @param with_guests: if True, get affiliations of people invited by email 776 @param with_guests: if True, get affiliations of people invited by email
742 777
743 """ 778 """
744 entities = client.roster.getJids() + [client.jid.userhostJID()] 779 if client.is_component:
780 entities = [client.jid.userhostJID()]
781 else:
782 entities = client.roster.getJids() + [client.jid.userhostJID()]
745 783
746 return await self.getIdentities( 784 return await self.getIdentities(
747 client, 785 client,
748 entities, 786 entities,
749 ['avatar', 'nicknames'] 787 ['avatar', 'nicknames']
755 return defer.ensureDeferred(self.setIdentity(client, id_data)) 793 return defer.ensureDeferred(self.setIdentity(client, id_data))
756 794
757 async def setIdentity(self, client, id_data): 795 async def setIdentity(self, client, id_data):
758 """Update profile's identity 796 """Update profile's identity
759 797
760 @param id_data(dict): data to update, key can be on of self.metadata keys 798 @param id_data(dict): data to update, key can be one of self.metadata keys
761 """ 799 """
762 if not id_data.keys() <= self.metadata.keys(): 800 if not id_data.keys() <= self.metadata.keys():
763 raise ValueError( 801 raise ValueError(
764 f"Invalid metadata names: {id_data.keys() - self.metadata.keys()}") 802 f"Invalid metadata names: {id_data.keys() - self.metadata.keys()}")
765 for metadata_name, data in id_data.items(): 803 for metadata_name, data in id_data.items():