comparison sat/plugins/plugin_xep_0277.py @ 4037:524856bd7b19

massive refactoring to switch from camelCase to snake_case: historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a pre-PEP8 code, to use the same coding style as in Twisted. However, snake_case is more readable and it's better to follow PEP8 best practices, so it has been decided to move on full snake_case. Because Libervia has a huge codebase, this ended with a ugly mix of camelCase and snake_case. To fix that, this patch does a big refactoring by renaming every function and method (including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case. This is a massive change, and may result in some bugs.
author Goffi <goffi@goffi.org>
date Sat, 08 Apr 2023 13:54:42 +0200
parents 78b5f356900c
children
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
82 NS_ATOM = NS_ATOM 82 NS_ATOM = NS_ATOM
83 83
84 def __init__(self, host): 84 def __init__(self, host):
85 log.info(_("Microblogging plugin initialization")) 85 log.info(_("Microblogging plugin initialization"))
86 self.host = host 86 self.host = host
87 host.registerNamespace("microblog", NS_MICROBLOG) 87 host.register_namespace("microblog", NS_MICROBLOG)
88 self._p = self.host.plugins[ 88 self._p = self.host.plugins[
89 "XEP-0060" 89 "XEP-0060"
90 ] # this facilitate the access to pubsub plugin 90 ] # this facilitate the access to pubsub plugin
91 ps_cache = self.host.plugins.get("PUBSUB_CACHE") 91 ps_cache = self.host.plugins.get("PUBSUB_CACHE")
92 if ps_cache is not None: 92 if ps_cache is not None:
93 ps_cache.registerAnalyser( 93 ps_cache.register_analyser(
94 { 94 {
95 "name": "XEP-0277", 95 "name": "XEP-0277",
96 "node": NS_MICROBLOG, 96 "node": NS_MICROBLOG,
97 "namespace": NS_ATOM, 97 "namespace": NS_ATOM,
98 "type": "blog", 98 "type": "blog",
99 "to_sync": True, 99 "to_sync": True,
100 "parser": self.item_2_mb_data, 100 "parser": self.item_2_mb_data,
101 "match_cb": self._cacheNodeMatchCb, 101 "match_cb": self._cache_node_match_cb,
102 } 102 }
103 ) 103 )
104 self.rt_sessions = sat_defer.RTDeferredSessions() 104 self.rt_sessions = sat_defer.RTDeferredSessions()
105 self.host.plugins["XEP-0060"].addManagedNode( 105 self.host.plugins["XEP-0060"].add_managed_node(
106 NS_MICROBLOG, items_cb=self._itemsReceived 106 NS_MICROBLOG, items_cb=self._items_received
107 ) 107 )
108 108
109 host.bridge.addMethod( 109 host.bridge.add_method(
110 "mbSend", 110 "mb_send",
111 ".plugin", 111 ".plugin",
112 in_sign="ssss", 112 in_sign="ssss",
113 out_sign="s", 113 out_sign="s",
114 method=self._mbSend, 114 method=self._mb_send,
115 async_=True, 115 async_=True,
116 ) 116 )
117 host.bridge.addMethod( 117 host.bridge.add_method(
118 "mbRepeat", 118 "mb_repeat",
119 ".plugin", 119 ".plugin",
120 in_sign="sssss", 120 in_sign="sssss",
121 out_sign="s", 121 out_sign="s",
122 method=self._mbRepeat, 122 method=self._mb_repeat,
123 async_=True, 123 async_=True,
124 ) 124 )
125 host.bridge.addMethod( 125 host.bridge.add_method(
126 "mbPreview", 126 "mb_preview",
127 ".plugin", 127 ".plugin",
128 in_sign="ssss", 128 in_sign="ssss",
129 out_sign="s", 129 out_sign="s",
130 method=self._mbPreview, 130 method=self._mb_preview,
131 async_=True, 131 async_=True,
132 ) 132 )
133 host.bridge.addMethod( 133 host.bridge.add_method(
134 "mbRetract", 134 "mb_retract",
135 ".plugin", 135 ".plugin",
136 in_sign="ssss", 136 in_sign="ssss",
137 out_sign="", 137 out_sign="",
138 method=self._mbRetract, 138 method=self._mb_retract,
139 async_=True, 139 async_=True,
140 ) 140 )
141 host.bridge.addMethod( 141 host.bridge.add_method(
142 "mbGet", 142 "mb_get",
143 ".plugin", 143 ".plugin",
144 in_sign="ssiasss", 144 in_sign="ssiasss",
145 out_sign="s", 145 out_sign="s",
146 method=self._mbGet, 146 method=self._mb_get,
147 async_=True, 147 async_=True,
148 ) 148 )
149 host.bridge.addMethod( 149 host.bridge.add_method(
150 "mbRename", 150 "mb_rename",
151 ".plugin", 151 ".plugin",
152 in_sign="sssss", 152 in_sign="sssss",
153 out_sign="", 153 out_sign="",
154 method=self._mbRename, 154 method=self._mb_rename,
155 async_=True, 155 async_=True,
156 ) 156 )
157 host.bridge.addMethod( 157 host.bridge.add_method(
158 "mbSetAccess", 158 "mb_access_set",
159 ".plugin", 159 ".plugin",
160 in_sign="ss", 160 in_sign="ss",
161 out_sign="", 161 out_sign="",
162 method=self.mbSetAccess, 162 method=self.mb_access_set,
163 async_=True, 163 async_=True,
164 ) 164 )
165 host.bridge.addMethod( 165 host.bridge.add_method(
166 "mbSubscribeToMany", 166 "mb_subscribe_to_many",
167 ".plugin", 167 ".plugin",
168 in_sign="sass", 168 in_sign="sass",
169 out_sign="s", 169 out_sign="s",
170 method=self._mbSubscribeToMany, 170 method=self._mb_subscribe_to_many,
171 ) 171 )
172 host.bridge.addMethod( 172 host.bridge.add_method(
173 "mbGetFromManyRTResult", 173 "mb_get_from_many_rt_result",
174 ".plugin", 174 ".plugin",
175 in_sign="ss", 175 in_sign="ss",
176 out_sign="(ua(sssasa{ss}))", 176 out_sign="(ua(sssasa{ss}))",
177 method=self._mbGetFromManyRTResult, 177 method=self._mb_get_from_many_rt_result,
178 async_=True, 178 async_=True,
179 ) 179 )
180 host.bridge.addMethod( 180 host.bridge.add_method(
181 "mbGetFromMany", 181 "mb_get_from_many",
182 ".plugin", 182 ".plugin",
183 in_sign="sasia{ss}s", 183 in_sign="sasia{ss}s",
184 out_sign="s", 184 out_sign="s",
185 method=self._mbGetFromMany, 185 method=self._mb_get_from_many,
186 ) 186 )
187 host.bridge.addMethod( 187 host.bridge.add_method(
188 "mbGetFromManyWithCommentsRTResult", 188 "mb_get_from_many_with_comments_rt_result",
189 ".plugin", 189 ".plugin",
190 in_sign="ss", 190 in_sign="ss",
191 out_sign="(ua(sssa(sa(sssasa{ss}))a{ss}))", 191 out_sign="(ua(sssa(sa(sssasa{ss}))a{ss}))",
192 method=self._mbGetFromManyWithCommentsRTResult, 192 method=self._mb_get_from_many_with_comments_rt_result,
193 async_=True, 193 async_=True,
194 ) 194 )
195 host.bridge.addMethod( 195 host.bridge.add_method(
196 "mbGetFromManyWithComments", 196 "mb_get_from_many_with_comments",
197 ".plugin", 197 ".plugin",
198 in_sign="sasiia{ss}a{ss}s", 198 in_sign="sasiia{ss}a{ss}s",
199 out_sign="s", 199 out_sign="s",
200 method=self._mbGetFromManyWithComments, 200 method=self._mb_get_from_many_with_comments,
201 ) 201 )
202 host.bridge.addMethod( 202 host.bridge.add_method(
203 "mbIsCommentNode", 203 "mb_is_comment_node",
204 ".plugin", 204 ".plugin",
205 in_sign="s", 205 in_sign="s",
206 out_sign="b", 206 out_sign="b",
207 method=self.isCommentNode, 207 method=self.is_comment_node,
208 ) 208 )
209 209
210 def getHandler(self, client): 210 def get_handler(self, client):
211 return XEP_0277_handler() 211 return XEP_0277_handler()
212 212
213 def _cacheNodeMatchCb( 213 def _cache_node_match_cb(
214 self, 214 self,
215 client: SatXMPPEntity, 215 client: SatXMPPEntity,
216 analyse: dict, 216 analyse: dict,
217 ) -> None: 217 ) -> None:
218 """Check is analysed node is a comment and fill analyse accordingly""" 218 """Check is analysed node is a comment and fill analyse accordingly"""
219 if analyse["node"].startswith(NS_COMMENT_PREFIX): 219 if analyse["node"].startswith(NS_COMMENT_PREFIX):
220 analyse["subtype"] = "comment" 220 analyse["subtype"] = "comment"
221 221
222 def _checkFeaturesCb(self, available): 222 def _check_features_cb(self, available):
223 return {"available": C.BOOL_TRUE} 223 return {"available": C.BOOL_TRUE}
224 224
225 def _checkFeaturesEb(self, fail): 225 def _check_features_eb(self, fail):
226 return {"available": C.BOOL_FALSE} 226 return {"available": C.BOOL_FALSE}
227 227
228 def getFeatures(self, profile): 228 def features_get(self, profile):
229 client = self.host.getClient(profile) 229 client = self.host.get_client(profile)
230 d = self.host.checkFeatures(client, [], identity=("pubsub", "pep")) 230 d = self.host.check_features(client, [], identity=("pubsub", "pep"))
231 d.addCallbacks(self._checkFeaturesCb, self._checkFeaturesEb) 231 d.addCallbacks(self._check_features_cb, self._check_features_eb)
232 return d 232 return d
233 233
234 ## plugin management methods ## 234 ## plugin management methods ##
235 235
236 def _itemsReceived(self, client, itemsEvent): 236 def _items_received(self, client, itemsEvent):
237 """Callback which manage items notifications (publish + retract)""" 237 """Callback which manage items notifications (publish + retract)"""
238 238
239 def manageItem(data, event): 239 def manage_item(data, event):
240 self.host.bridge.psEvent( 240 self.host.bridge.ps_event(
241 C.PS_MICROBLOG, 241 C.PS_MICROBLOG,
242 itemsEvent.sender.full(), 242 itemsEvent.sender.full(),
243 itemsEvent.nodeIdentifier, 243 itemsEvent.nodeIdentifier,
244 event, 244 event,
245 data_format.serialise(data), 245 data_format.serialise(data),
248 248
249 for item in itemsEvent.items: 249 for item in itemsEvent.items:
250 if item.name == C.PS_ITEM: 250 if item.name == C.PS_ITEM:
251 # FIXME: service and node should be used here 251 # FIXME: service and node should be used here
252 self.item_2_mb_data(client, item, None, None).addCallbacks( 252 self.item_2_mb_data(client, item, None, None).addCallbacks(
253 manageItem, lambda failure: None, (C.PS_PUBLISH,) 253 manage_item, lambda failure: None, (C.PS_PUBLISH,)
254 ) 254 )
255 elif item.name == C.PS_RETRACT: 255 elif item.name == C.PS_RETRACT:
256 manageItem({"id": item["id"]}, C.PS_RETRACT) 256 manage_item({"id": item["id"]}, C.PS_RETRACT)
257 else: 257 else:
258 raise exceptions.InternalError("Invalid event value") 258 raise exceptions.InternalError("Invalid event value")
259 259
260 ## data/item transformation ## 260 ## data/item transformation ##
261 261
332 _("Content of type XHTML must declare its namespace!") 332 _("Content of type XHTML must declare its namespace!")
333 ) 333 )
334 ) 334 )
335 key = check_conflict("{}_xhtml".format(elem.name)) 335 key = check_conflict("{}_xhtml".format(elem.name))
336 data = data_elt.toXml() 336 data = data_elt.toXml()
337 microblog_data[key] = yield self.host.plugins["TEXT_SYNTAXES"].cleanXHTML( 337 microblog_data[key] = yield self.host.plugins["TEXT_SYNTAXES"].clean_xhtml(
338 data 338 data
339 ) 339 )
340 else: 340 else:
341 key = check_conflict(elem.name) 341 key = check_conflict(elem.name)
342 microblog_data[key] = str(elem) 342 microblog_data[key] = str(elem)
358 358
359 # uri 359 # uri
360 # FIXME: node should alway be set in the future, check FIXME in method signature 360 # FIXME: node should alway be set in the future, check FIXME in method signature
361 if node is not None: 361 if node is not None:
362 microblog_data["node"] = node 362 microblog_data["node"] = node
363 microblog_data['uri'] = xmpp_uri.buildXMPPUri( 363 microblog_data['uri'] = xmpp_uri.build_xmpp_uri(
364 "pubsub", 364 "pubsub",
365 path=service.full(), 365 path=service.full(),
366 node=node, 366 node=node,
367 item=id_, 367 item=id_,
368 ) 368 )
464 uri = href 464 uri = href
465 comments_data = { 465 comments_data = {
466 "uri": uri, 466 "uri": uri,
467 } 467 }
468 try: 468 try:
469 comment_service, comment_node = self.parseCommentUrl(uri) 469 comment_service, comment_node = self.parse_comment_url(uri)
470 except Exception as e: 470 except Exception as e:
471 log.warning(f"Can't parse comments url: {e}") 471 log.warning(f"Can't parse comments url: {e}")
472 continue 472 continue
473 else: 473 else:
474 comments_data["service"] = comment_service.full() 474 comments_data["service"] = comment_service.full()
594 if not microblog_data.get("author_jid"): 594 if not microblog_data.get("author_jid"):
595 if publisher: 595 if publisher:
596 microblog_data["author_jid"] = publisher 596 microblog_data["author_jid"] = publisher
597 microblog_data["author_jid_verified"] = True 597 microblog_data["author_jid_verified"] = True
598 else: 598 else:
599 iq_elt = xml_tools.findAncestor(item_elt, "iq", C.NS_STREAM) 599 iq_elt = xml_tools.find_ancestor(item_elt, "iq", C.NS_STREAM)
600 microblog_data["author_jid"] = iq_elt["from"] 600 microblog_data["author_jid"] = iq_elt["from"]
601 microblog_data["author_jid_verified"] = False 601 microblog_data["author_jid_verified"] = False
602 602
603 # categories 603 # categories
604 categories = [ 604 categories = [
642 if attr in mb_data: 642 if attr in mb_data:
643 elem = entry_elt.addElement(elem_name) 643 elem = entry_elt.addElement(elem_name)
644 if type_: 644 if type_:
645 if type_ == "_rich": # convert input from current syntax to XHTML 645 if type_ == "_rich": # convert input from current syntax to XHTML
646 xml_content = await synt.convert( 646 xml_content = await synt.convert(
647 mb_data[attr], synt.getCurrentSyntax(client.profile), "XHTML" 647 mb_data[attr], synt.get_current_syntax(client.profile), "XHTML"
648 ) 648 )
649 if f"{elem_name}_xhtml" in mb_data: 649 if f"{elem_name}_xhtml" in mb_data:
650 raise failure.Failure( 650 raise failure.Failure(
651 exceptions.DataError( 651 exceptions.DataError(
652 _( 652 _(
722 722
723 if not url.startswith("http"): 723 if not url.startswith("http"):
724 log.warning(f"non HTTP URL in attachment, ignoring: {attachment}") 724 log.warning(f"non HTTP URL in attachment, ignoring: {attachment}")
725 continue 725 continue
726 link_elt = entry_elt.addElement("link") 726 link_elt = entry_elt.addElement("link")
727 # XXX: "uri" is set in self._manageComments if not already existing 727 # XXX: "uri" is set in self._manage_comments if not already existing
728 link_elt["href"] = url 728 link_elt["href"] = url
729 if attachment.get("external", False): 729 if attachment.get("external", False):
730 # this is a link to an external data such as a website 730 # this is a link to an external data such as a website
731 link_elt["rel"] = "related" 731 link_elt["rel"] = "related"
732 else: 732 else:
777 category_elt["term"] = tag 777 category_elt["term"] = tag
778 778
779 ## id ## 779 ## id ##
780 entry_id = mb_data.get( 780 entry_id = mb_data.get(
781 "id", 781 "id",
782 xmpp_uri.buildXMPPUri( 782 xmpp_uri.build_xmpp_uri(
783 "pubsub", 783 "pubsub",
784 path=service.full() if service is not None else client.jid.userhost(), 784 path=service.full() if service is not None else client.jid.userhost(),
785 node=node, 785 node=node,
786 item=item_id, 786 item=item_id,
787 ), 787 ),
789 entry_elt.addElement("id", content=entry_id) # 789 entry_elt.addElement("id", content=entry_id) #
790 790
791 ## comments ## 791 ## comments ##
792 for comments_data in mb_data.get('comments', []): 792 for comments_data in mb_data.get('comments', []):
793 link_elt = entry_elt.addElement("link") 793 link_elt = entry_elt.addElement("link")
794 # XXX: "uri" is set in self._manageComments if not already existing 794 # XXX: "uri" is set in self._manage_comments if not already existing
795 link_elt["href"] = comments_data["uri"] 795 link_elt["href"] = comments_data["uri"]
796 link_elt["rel"] = "replies" 796 link_elt["rel"] = "replies"
797 link_elt["title"] = "comments" 797 link_elt["title"] = "comments"
798 798
799 if "repeated" in extra: 799 if "repeated" in extra:
818 818
819 return item_elt 819 return item_elt
820 820
821 ## publish/preview ## 821 ## publish/preview ##
822 822
823 def isCommentNode(self, node: str) -> bool: 823 def is_comment_node(self, node: str) -> bool:
824 """Indicate if the node is prefixed with comments namespace""" 824 """Indicate if the node is prefixed with comments namespace"""
825 return node.startswith(NS_COMMENT_PREFIX) 825 return node.startswith(NS_COMMENT_PREFIX)
826 826
827 def getParentItem(self, item_id: str) -> str: 827 def get_parent_item(self, item_id: str) -> str:
828 """Return parent of a comment node 828 """Return parent of a comment node
829 829
830 @param item_id: a comment node 830 @param item_id: a comment node
831 """ 831 """
832 if not self.isCommentNode(item_id): 832 if not self.is_comment_node(item_id):
833 raise ValueError("This node is not a comment node") 833 raise ValueError("This node is not a comment node")
834 return item_id[len(NS_COMMENT_PREFIX):] 834 return item_id[len(NS_COMMENT_PREFIX):]
835 835
836 def getCommentsNode(self, item_id): 836 def get_comments_node(self, item_id):
837 """Generate comment node 837 """Generate comment node
838 838
839 @param item_id(unicode): id of the parent item 839 @param item_id(unicode): id of the parent item
840 @return (unicode): comment node to use 840 @return (unicode): comment node to use
841 """ 841 """
842 return f"{NS_COMMENT_PREFIX}{item_id}" 842 return f"{NS_COMMENT_PREFIX}{item_id}"
843 843
844 def getCommentsService(self, client, parent_service=None): 844 def get_comments_service(self, client, parent_service=None):
845 """Get prefered PubSub service to create comment node 845 """Get prefered PubSub service to create comment node
846 846
847 @param pubsub_service(jid.JID, None): PubSub service of the parent item 847 @param pubsub_service(jid.JID, None): PubSub service of the parent item
848 @param return((D)jid.JID, None): PubSub service to use 848 @param return((D)jid.JID, None): PubSub service to use
849 """ 849 """
853 if parent_service.host == client.jid.host: 853 if parent_service.host == client.jid.host:
854 #  it's our server, we use already found client.pubsub_service below 854 #  it's our server, we use already found client.pubsub_service below
855 pass 855 pass
856 else: 856 else:
857 # other server, let's try to find a non PEP service there 857 # other server, let's try to find a non PEP service there
858 d = self.host.findServiceEntity( 858 d = self.host.find_service_entity(
859 client, "pubsub", "service", parent_service 859 client, "pubsub", "service", parent_service
860 ) 860 )
861 d.addCallback(lambda entity: entity or parent_service) 861 d.addCallback(lambda entity: entity or parent_service)
862 else: 862 else:
863 # parent is already on a normal Pubsub service, we re-use it 863 # parent is already on a normal Pubsub service, we re-use it
865 865
866 return defer.succeed( 866 return defer.succeed(
867 client.pubsub_service if client.pubsub_service is not None else parent_service 867 client.pubsub_service if client.pubsub_service is not None else parent_service
868 ) 868 )
869 869
870 async def _manageComments(self, client, mb_data, service, node, item_id, access=None): 870 async def _manage_comments(self, client, mb_data, service, node, item_id, access=None):
871 """Check comments keys in mb_data and create comments node if necessary 871 """Check comments keys in mb_data and create comments node if necessary
872 872
873 if a comments node metadata is set in the mb_data['comments'] list, it is used 873 if a comments node metadata is set in the mb_data['comments'] list, it is used
874 otherwise it is generated (if allow_comments is True). 874 otherwise it is generated (if allow_comments is True).
875 @param mb_data(dict): microblog mb_data 875 @param mb_data(dict): microblog mb_data
929 comments_service = jid.JID(comments_data["service"]) 929 comments_service = jid.JID(comments_data["service"])
930 except KeyError: 930 except KeyError:
931 comments_service = None 931 comments_service = None
932 932
933 if uri: 933 if uri:
934 uri_service, uri_node = self.parseCommentUrl(uri) 934 uri_service, uri_node = self.parse_comment_url(uri)
935 if ((comments_node is not None and comments_node!=uri_node) 935 if ((comments_node is not None and comments_node!=uri_node)
936 or (comments_service is not None and comments_service!=uri_service)): 936 or (comments_service is not None and comments_service!=uri_service)):
937 raise ValueError( 937 raise ValueError(
938 f"Incoherence between comments URI ({uri}) and comments_service " 938 f"Incoherence between comments URI ({uri}) and comments_service "
939 f"({comments_service}) or comments_node ({comments_node})") 939 f"({comments_service}) or comments_node ({comments_node})")
940 comments_data['service'] = comments_service = uri_service 940 comments_data['service'] = comments_service = uri_service
941 comments_data['node'] = comments_node = uri_node 941 comments_data['node'] = comments_node = uri_node
942 else: 942 else:
943 if not comments_node: 943 if not comments_node:
944 comments_node = self.getCommentsNode(item_id) 944 comments_node = self.get_comments_node(item_id)
945 comments_data['node'] = comments_node 945 comments_data['node'] = comments_node
946 if comments_service is None: 946 if comments_service is None:
947 comments_service = await self.getCommentsService(client, service) 947 comments_service = await self.get_comments_service(client, service)
948 if comments_service is None: 948 if comments_service is None:
949 comments_service = client.jid.userhostJID() 949 comments_service = client.jid.userhostJID()
950 comments_data['service'] = comments_service 950 comments_data['service'] = comments_service
951 951
952 comments_data['uri'] = xmpp_uri.buildXMPPUri( 952 comments_data['uri'] = xmpp_uri.build_xmpp_uri(
953 "pubsub", 953 "pubsub",
954 path=comments_service.full(), 954 path=comments_service.full(),
955 node=comments_node, 955 node=comments_node,
956 ) 956 )
957 957
967 else: 967 else:
968 raise e 968 raise e
969 else: 969 else:
970 if access == self._p.ACCESS_WHITELIST: 970 if access == self._p.ACCESS_WHITELIST:
971 # for whitelist access we need to copy affiliations from parent item 971 # for whitelist access we need to copy affiliations from parent item
972 comments_affiliations = await self._p.getNodeAffiliations( 972 comments_affiliations = await self._p.get_node_affiliations(
973 client, service, node 973 client, service, node
974 ) 974 )
975 # …except for "member", that we transform to publisher 975 # …except for "member", that we transform to publisher
976 # because we wants members to be able to write to comments 976 # because we wants members to be able to write to comments
977 for jid_, affiliation in list(comments_affiliations.items()): 977 for jid_, affiliation in list(comments_affiliations.items()):
978 if affiliation == "member": 978 if affiliation == "member":
979 comments_affiliations[jid_] == "publisher" 979 comments_affiliations[jid_] == "publisher"
980 980
981 await self._p.setNodeAffiliations( 981 await self._p.set_node_affiliations(
982 client, comments_service, comments_node, comments_affiliations 982 client, comments_service, comments_node, comments_affiliations
983 ) 983 )
984 984
985 def friendlyId(self, data): 985 def friendly_id(self, data):
986 """Generate a user friendly id from title or content""" 986 """Generate a user friendly id from title or content"""
987 # TODO: rich content should be converted to plain text 987 # TODO: rich content should be converted to plain text
988 id_base = regex.urlFriendlyText( 988 id_base = regex.url_friendly_text(
989 data.get('title') 989 data.get('title')
990 or data.get('title_rich') 990 or data.get('title_rich')
991 or data.get('content') 991 or data.get('content')
992 or data.get('content_rich') 992 or data.get('content_rich')
993 or '' 993 or ''
994 ) 994 )
995 return f"{id_base}-{token_urlsafe(3)}" 995 return f"{id_base}-{token_urlsafe(3)}"
996 996
997 def _mbSend(self, service, node, data, profile_key): 997 def _mb_send(self, service, node, data, profile_key):
998 service = jid.JID(service) if service else None 998 service = jid.JID(service) if service else None
999 node = node if node else NS_MICROBLOG 999 node = node if node else NS_MICROBLOG
1000 client = self.host.getClient(profile_key) 1000 client = self.host.get_client(profile_key)
1001 data = data_format.deserialise(data) 1001 data = data_format.deserialise(data)
1002 return defer.ensureDeferred(self.send(client, data, service, node)) 1002 return defer.ensureDeferred(self.send(client, data, service, node))
1003 1003
1004 async def send( 1004 async def send(
1005 self, 1005 self,
1026 node = NS_MICROBLOG 1026 node = NS_MICROBLOG
1027 1027
1028 item_id = data.get("id") 1028 item_id = data.get("id")
1029 if item_id is None: 1029 if item_id is None:
1030 if data.get("user_friendly_id", True): 1030 if data.get("user_friendly_id", True):
1031 item_id = self.friendlyId(data) 1031 item_id = self.friendly_id(data)
1032 else: 1032 else:
1033 item_id = str(shortuuid.uuid()) 1033 item_id = str(shortuuid.uuid())
1034 1034
1035 try: 1035 try:
1036 await self._manageComments(client, data, service, node, item_id, access=None) 1036 await self._manage_comments(client, data, service, node, item_id, access=None)
1037 except error.StanzaError: 1037 except error.StanzaError:
1038 log.warning("Can't create comments node for item {}".format(item_id)) 1038 log.warning("Can't create comments node for item {}".format(item_id))
1039 item = await self.mb_data_2_entry_elt(client, data, item_id, service, node) 1039 item = await self.mb_data_2_entry_elt(client, data, item_id, service, node)
1040 1040
1041 if not await self.host.trigger.asyncPoint( 1041 if not await self.host.trigger.async_point(
1042 "XEP-0277_send", client, service, node, item, data 1042 "XEP-0277_send", client, service, node, item, data
1043 ): 1043 ):
1044 return None 1044 return None
1045 1045
1046 extra = {} 1046 extra = {}
1050 extra[key] = value 1050 extra[key] = value
1051 1051
1052 await self._p.publish(client, service, node, [item], extra=extra) 1052 await self._p.publish(client, service, node, [item], extra=extra)
1053 return item_id 1053 return item_id
1054 1054
1055 def _mbRepeat( 1055 def _mb_repeat(
1056 self, 1056 self,
1057 service_s: str, 1057 service_s: str,
1058 node: str, 1058 node: str,
1059 item: str, 1059 item: str,
1060 extra_s: str, 1060 extra_s: str,
1061 profile_key: str 1061 profile_key: str
1062 ) -> defer.Deferred: 1062 ) -> defer.Deferred:
1063 service = jid.JID(service_s) if service_s else None 1063 service = jid.JID(service_s) if service_s else None
1064 node = node if node else NS_MICROBLOG 1064 node = node if node else NS_MICROBLOG
1065 client = self.host.getClient(profile_key) 1065 client = self.host.get_client(profile_key)
1066 extra = data_format.deserialise(extra_s) 1066 extra = data_format.deserialise(extra_s)
1067 d = defer.ensureDeferred( 1067 d = defer.ensureDeferred(
1068 self.repeat(client, item, service, node, extra) 1068 self.repeat(client, item, service, node, extra)
1069 ) 1069 )
1070 # [repeat] can return None, and we always need a str 1070 # [repeat] can return None, and we always need a str
1086 """ 1086 """
1087 if service is None: 1087 if service is None:
1088 service = client.jid.userhostJID() 1088 service = client.jid.userhostJID()
1089 1089
1090 # we first get the post to repeat 1090 # we first get the post to repeat
1091 items, __ = await self._p.getItems( 1091 items, __ = await self._p.get_items(
1092 client, 1092 client,
1093 service, 1093 service,
1094 node, 1094 node,
1095 item_ids = [item] 1095 item_ids = [item]
1096 ) 1096 )
1119 1119
1120 try: 1120 try:
1121 next(author_elt.elements(NS_ATOM, "uri")) 1121 next(author_elt.elements(NS_ATOM, "uri"))
1122 except StopIteration: 1122 except StopIteration:
1123 entry_elt.addElement( 1123 entry_elt.addElement(
1124 "uri", content=xmpp_uri.buildXMPPUri(None, path=service.full()) 1124 "uri", content=xmpp_uri.build_xmpp_uri(None, path=service.full())
1125 ) 1125 )
1126 1126
1127 # we add the link indicating that it's a repeated post 1127 # we add the link indicating that it's a repeated post
1128 link_elt = entry_elt.addElement("link") 1128 link_elt = entry_elt.addElement("link")
1129 link_elt["rel"] = "via" 1129 link_elt["rel"] = "via"
1130 link_elt["href"] = xmpp_uri.buildXMPPUri( 1130 link_elt["href"] = xmpp_uri.build_xmpp_uri(
1131 "pubsub", path=service.full(), node=node, item=item 1131 "pubsub", path=service.full(), node=node, item=item
1132 ) 1132 )
1133 1133
1134 return await self._p.sendItem( 1134 return await self._p.send_item(
1135 client, 1135 client,
1136 client.jid.userhostJID(), 1136 client.jid.userhostJID(),
1137 NS_MICROBLOG, 1137 NS_MICROBLOG,
1138 entry_elt 1138 entry_elt
1139 ) 1139 )
1140 1140
1141 def _mbPreview(self, service, node, data, profile_key): 1141 def _mb_preview(self, service, node, data, profile_key):
1142 service = jid.JID(service) if service else None 1142 service = jid.JID(service) if service else None
1143 node = node if node else NS_MICROBLOG 1143 node = node if node else NS_MICROBLOG
1144 client = self.host.getClient(profile_key) 1144 client = self.host.get_client(profile_key)
1145 data = data_format.deserialise(data) 1145 data = data_format.deserialise(data)
1146 d = defer.ensureDeferred(self.preview(client, data, service, node)) 1146 d = defer.ensureDeferred(self.preview(client, data, service, node))
1147 d.addCallback(data_format.serialise) 1147 d.addCallback(data_format.serialise)
1148 return d 1148 return d
1149 1149
1170 return await self.item_2_mb_data(client, item_elt, service, node) 1170 return await self.item_2_mb_data(client, item_elt, service, node)
1171 1171
1172 1172
1173 ## retract ## 1173 ## retract ##
1174 1174
1175 def _mbRetract(self, service_jid_s, nodeIdentifier, itemIdentifier, profile_key): 1175 def _mb_retract(self, service_jid_s, nodeIdentifier, itemIdentifier, profile_key):
1176 """Call self._p._retractItem, but use default node if node is empty""" 1176 """Call self._p._retract_item, but use default node if node is empty"""
1177 return self._p._retractItem( 1177 return self._p._retract_item(
1178 service_jid_s, 1178 service_jid_s,
1179 nodeIdentifier or NS_MICROBLOG, 1179 nodeIdentifier or NS_MICROBLOG,
1180 itemIdentifier, 1180 itemIdentifier,
1181 True, 1181 True,
1182 profile_key, 1182 profile_key,
1183 ) 1183 )
1184 1184
1185 ## get ## 1185 ## get ##
1186 1186
1187 def _mbGetSerialise(self, data): 1187 def _mb_get_serialise(self, data):
1188 items, metadata = data 1188 items, metadata = data
1189 metadata['items'] = items 1189 metadata['items'] = items
1190 return data_format.serialise(metadata) 1190 return data_format.serialise(metadata)
1191 1191
1192 def _mbGet(self, service="", node="", max_items=10, item_ids=None, extra="", 1192 def _mb_get(self, service="", node="", max_items=10, item_ids=None, extra="",
1193 profile_key=C.PROF_KEY_NONE): 1193 profile_key=C.PROF_KEY_NONE):
1194 """ 1194 """
1195 @param max_items(int): maximum number of item to get, C.NO_LIMIT for no limit 1195 @param max_items(int): maximum number of item to get, C.NO_LIMIT for no limit
1196 @param item_ids (list[unicode]): list of item IDs 1196 @param item_ids (list[unicode]): list of item IDs
1197 """ 1197 """
1198 client = self.host.getClient(profile_key) 1198 client = self.host.get_client(profile_key)
1199 service = jid.JID(service) if service else None 1199 service = jid.JID(service) if service else None
1200 max_items = None if max_items == C.NO_LIMIT else max_items 1200 max_items = None if max_items == C.NO_LIMIT else max_items
1201 extra = self._p.parseExtra(data_format.deserialise(extra)) 1201 extra = self._p.parse_extra(data_format.deserialise(extra))
1202 d = defer.ensureDeferred( 1202 d = defer.ensureDeferred(
1203 self.mbGet(client, service, node or None, max_items, item_ids, 1203 self.mb_get(client, service, node or None, max_items, item_ids,
1204 extra.rsm_request, extra.extra) 1204 extra.rsm_request, extra.extra)
1205 ) 1205 )
1206 d.addCallback(self._mbGetSerialise) 1206 d.addCallback(self._mb_get_serialise)
1207 return d 1207 return d
1208 1208
1209 async def mbGet( 1209 async def mb_get(
1210 self, 1210 self,
1211 client: SatXMPPEntity, 1211 client: SatXMPPEntity,
1212 service: Optional[jid.JID] = None, 1212 service: Optional[jid.JID] = None,
1213 node: Optional[str] = None, 1213 node: Optional[str] = None,
1214 max_items: Optional[int] = 10, 1214 max_items: Optional[int] = 10,
1231 """ 1231 """
1232 if node is None: 1232 if node is None:
1233 node = NS_MICROBLOG 1233 node = NS_MICROBLOG
1234 if rsm_request: 1234 if rsm_request:
1235 max_items = None 1235 max_items = None
1236 items_data = await self._p.getItems( 1236 items_data = await self._p.get_items(
1237 client, 1237 client,
1238 service, 1238 service,
1239 node, 1239 node,
1240 max_items=max_items, 1240 max_items=max_items,
1241 item_ids=item_ids, 1241 item_ids=item_ids,
1242 rsm_request=rsm_request, 1242 rsm_request=rsm_request,
1243 extra=extra, 1243 extra=extra,
1244 ) 1244 )
1245 mb_data_list, metadata = await self._p.transItemsDataD( 1245 mb_data_list, metadata = await self._p.trans_items_data_d(
1246 items_data, partial(self.item_2_mb_data, client, service=service, node=node)) 1246 items_data, partial(self.item_2_mb_data, client, service=service, node=node))
1247 encrypted = metadata.pop("encrypted", None) 1247 encrypted = metadata.pop("encrypted", None)
1248 if encrypted is not None: 1248 if encrypted is not None:
1249 for mb_data in mb_data_list: 1249 for mb_data in mb_data_list:
1250 try: 1250 try:
1251 mb_data["encrypted"] = encrypted[mb_data["id"]] 1251 mb_data["encrypted"] = encrypted[mb_data["id"]]
1252 except KeyError: 1252 except KeyError:
1253 pass 1253 pass
1254 return (mb_data_list, metadata) 1254 return (mb_data_list, metadata)
1255 1255
1256 def _mbRename(self, service, node, item_id, new_id, profile_key): 1256 def _mb_rename(self, service, node, item_id, new_id, profile_key):
1257 return defer.ensureDeferred(self.mbRename( 1257 return defer.ensureDeferred(self.mb_rename(
1258 self.host.getClient(profile_key), 1258 self.host.get_client(profile_key),
1259 jid.JID(service) if service else None, 1259 jid.JID(service) if service else None,
1260 node or None, 1260 node or None,
1261 item_id, 1261 item_id,
1262 new_id 1262 new_id
1263 )) 1263 ))
1264 1264
1265 async def mbRename( 1265 async def mb_rename(
1266 self, 1266 self,
1267 client: SatXMPPEntity, 1267 client: SatXMPPEntity,
1268 service: Optional[jid.JID], 1268 service: Optional[jid.JID],
1269 node: Optional[str], 1269 node: Optional[str],
1270 item_id: str, 1270 item_id: str,
1271 new_id: str 1271 new_id: str
1272 ) -> None: 1272 ) -> None:
1273 if not node: 1273 if not node:
1274 node = NS_MICROBLOG 1274 node = NS_MICROBLOG
1275 await self._p.renameItem(client, service, node, item_id, new_id) 1275 await self._p.rename_item(client, service, node, item_id, new_id)
1276 1276
1277 def parseCommentUrl(self, node_url): 1277 def parse_comment_url(self, node_url):
1278 """Parse a XMPP URI 1278 """Parse a XMPP URI
1279 1279
1280 Determine the fields comments_service and comments_node of a microblog data 1280 Determine the fields comments_service and comments_node of a microblog data
1281 from the href attribute of an entry's link element. For example this input: 1281 from the href attribute of an entry's link element. For example this input:
1282 xmpp:sat-pubsub.example.net?;node=urn%3Axmpp%3Acomments%3A_af43b363-3259-4b2a-ba4c-1bc33aa87634__urn%3Axmpp%3Agroupblog%3Asomebody%40example.net 1282 xmpp:sat-pubsub.example.net?;node=urn%3Axmpp%3Acomments%3A_af43b363-3259-4b2a-ba4c-1bc33aa87634__urn%3Axmpp%3Agroupblog%3Asomebody%40example.net
1283 will return(JID(u'sat-pubsub.example.net'), 'urn:xmpp:comments:_af43b363-3259-4b2a-ba4c-1bc33aa87634__urn:xmpp:groupblog:somebody@example.net') 1283 will return(JID(u'sat-pubsub.example.net'), 'urn:xmpp:comments:_af43b363-3259-4b2a-ba4c-1bc33aa87634__urn:xmpp:groupblog:somebody@example.net')
1284 @return (tuple[jid.JID, unicode]): service and node 1284 @return (tuple[jid.JID, unicode]): service and node
1285 """ 1285 """
1286 try: 1286 try:
1287 parsed_url = xmpp_uri.parseXMPPUri(node_url) 1287 parsed_url = xmpp_uri.parse_xmpp_uri(node_url)
1288 service = jid.JID(parsed_url["path"]) 1288 service = jid.JID(parsed_url["path"])
1289 node = parsed_url["node"] 1289 node = parsed_url["node"]
1290 except Exception as e: 1290 except Exception as e:
1291 raise exceptions.DataError(f"Invalid comments link: {e}") 1291 raise exceptions.DataError(f"Invalid comments link: {e}")
1292 1292
1293 return (service, node) 1293 return (service, node)
1294 1294
1295 ## configure ## 1295 ## configure ##
1296 1296
1297 def mbSetAccess(self, access="presence", profile_key=C.PROF_KEY_NONE): 1297 def mb_access_set(self, access="presence", profile_key=C.PROF_KEY_NONE):
1298 """Create a microblog node on PEP with given access 1298 """Create a microblog node on PEP with given access
1299 1299
1300 If the node already exists, it change options 1300 If the node already exists, it change options
1301 @param access: Node access model, according to xep-0060 #4.5 1301 @param access: Node access model, according to xep-0060 #4.5
1302 @param profile_key: profile key 1302 @param profile_key: profile key
1303 """ 1303 """
1304 #  FIXME: check if this mehtod is need, deprecate it if not 1304 #  FIXME: check if this mehtod is need, deprecate it if not
1305 client = self.host.getClient(profile_key) 1305 client = self.host.get_client(profile_key)
1306 1306
1307 _options = { 1307 _options = {
1308 self._p.OPT_ACCESS_MODEL: access, 1308 self._p.OPT_ACCESS_MODEL: access,
1309 self._p.OPT_MAX_ITEMS: "max", 1309 self._p.OPT_MAX_ITEMS: "max",
1310 self._p.OPT_PERSIST_ITEMS: 1, 1310 self._p.OPT_PERSIST_ITEMS: 1,
1349 1349
1350 ## methods to manage several stanzas/jids at once ## 1350 ## methods to manage several stanzas/jids at once ##
1351 1351
1352 # common 1352 # common
1353 1353
1354 def _getClientAndNodeData(self, publishers_type, publishers, profile_key): 1354 def _get_client_and_node_data(self, publishers_type, publishers, profile_key):
1355 """Helper method to construct node_data from publishers_type/publishers 1355 """Helper method to construct node_data from publishers_type/publishers
1356 1356
1357 @param publishers_type: type of the list of publishers, one of: 1357 @param publishers_type: type of the list of publishers, one of:
1358 C.ALL: get all jids from roster, publishers is not used 1358 C.ALL: get all jids from roster, publishers is not used
1359 C.GROUP: get jids from groups 1359 C.GROUP: get jids from groups
1360 C.JID: use publishers directly as list of jids 1360 C.JID: use publishers directly as list of jids
1361 @param publishers: list of publishers, according to "publishers_type" (None, 1361 @param publishers: list of publishers, according to "publishers_type" (None,
1362 list of groups or list of jids) 1362 list of groups or list of jids)
1363 @param profile_key: %(doc_profile_key)s 1363 @param profile_key: %(doc_profile_key)s
1364 """ 1364 """
1365 client = self.host.getClient(profile_key) 1365 client = self.host.get_client(profile_key)
1366 if publishers_type == C.JID: 1366 if publishers_type == C.JID:
1367 jids_set = set(publishers) 1367 jids_set = set(publishers)
1368 else: 1368 else:
1369 jids_set = client.roster.getJidsSet(publishers_type, publishers) 1369 jids_set = client.roster.get_jids_set(publishers_type, publishers)
1370 if publishers_type == C.ALL: 1370 if publishers_type == C.ALL:
1371 try: 1371 try:
1372 # display messages from salut-a-toi@libervia.org or other PEP services 1372 # display messages from salut-a-toi@libervia.org or other PEP services
1373 services = self.host.plugins["EXTRA-PEP"].getFollowedEntities( 1373 services = self.host.plugins["EXTRA-PEP"].get_followed_entities(
1374 profile_key 1374 profile_key
1375 ) 1375 )
1376 except KeyError: 1376 except KeyError:
1377 pass # plugin is not loaded 1377 pass # plugin is not loaded
1378 else: 1378 else:
1386 node_data = [] 1386 node_data = []
1387 for jid_ in jids_set: 1387 for jid_ in jids_set:
1388 node_data.append((jid_, NS_MICROBLOG)) 1388 node_data.append((jid_, NS_MICROBLOG))
1389 return client, node_data 1389 return client, node_data
1390 1390
1391 def _checkPublishers(self, publishers_type, publishers): 1391 def _check_publishers(self, publishers_type, publishers):
1392 """Helper method to deserialise publishers coming from bridge 1392 """Helper method to deserialise publishers coming from bridge
1393 1393
1394 publishers_type(unicode): type of the list of publishers, one of: 1394 publishers_type(unicode): type of the list of publishers, one of:
1395 publishers: list of publishers according to type 1395 publishers: list of publishers according to type
1396 @return: deserialised (publishers_type, publishers) tuple 1396 @return: deserialised (publishers_type, publishers) tuple
1408 publishers[:] = [jid.JID(publisher) for publisher in publishers] 1408 publishers[:] = [jid.JID(publisher) for publisher in publishers]
1409 return publishers_type, publishers 1409 return publishers_type, publishers
1410 1410
1411 # subscribe # 1411 # subscribe #
1412 1412
1413 def _mbSubscribeToMany(self, publishers_type, publishers, profile_key): 1413 def _mb_subscribe_to_many(self, publishers_type, publishers, profile_key):
1414 """ 1414 """
1415 1415
1416 @return (str): session id: Use pubsub.getSubscribeRTResult to get the results 1416 @return (str): session id: Use pubsub.getSubscribeRTResult to get the results
1417 """ 1417 """
1418 publishers_type, publishers = self._checkPublishers(publishers_type, publishers) 1418 publishers_type, publishers = self._check_publishers(publishers_type, publishers)
1419 return self.mbSubscribeToMany(publishers_type, publishers, profile_key) 1419 return self.mb_subscribe_to_many(publishers_type, publishers, profile_key)
1420 1420
1421 def mbSubscribeToMany(self, publishers_type, publishers, profile_key): 1421 def mb_subscribe_to_many(self, publishers_type, publishers, profile_key):
1422 """Subscribe microblogs for a list of groups or jids 1422 """Subscribe microblogs for a list of groups or jids
1423 1423
1424 @param publishers_type: type of the list of publishers, one of: 1424 @param publishers_type: type of the list of publishers, one of:
1425 C.ALL: get all jids from roster, publishers is not used 1425 C.ALL: get all jids from roster, publishers is not used
1426 C.GROUP: get jids from groups 1426 C.GROUP: get jids from groups
1428 @param publishers: list of publishers, according to "publishers_type" (None, list 1428 @param publishers: list of publishers, according to "publishers_type" (None, list
1429 of groups or list of jids) 1429 of groups or list of jids)
1430 @param profile: %(doc_profile)s 1430 @param profile: %(doc_profile)s
1431 @return (str): session id 1431 @return (str): session id
1432 """ 1432 """
1433 client, node_data = self._getClientAndNodeData( 1433 client, node_data = self._get_client_and_node_data(
1434 publishers_type, publishers, profile_key 1434 publishers_type, publishers, profile_key
1435 ) 1435 )
1436 return self._p.subscribeToMany( 1436 return self._p.subscribe_to_many(
1437 node_data, client.jid.userhostJID(), profile_key=profile_key 1437 node_data, client.jid.userhostJID(), profile_key=profile_key
1438 ) 1438 )
1439 1439
1440 # get # 1440 # get #
1441 1441
1442 def _mbGetFromManyRTResult(self, session_id, profile_key=C.PROF_KEY_DEFAULT): 1442 def _mb_get_from_many_rt_result(self, session_id, profile_key=C.PROF_KEY_DEFAULT):
1443 """Get real-time results for mbGetFromMany session 1443 """Get real-time results for mb_get_from_many session
1444 1444
1445 @param session_id: id of the real-time deferred session 1445 @param session_id: id of the real-time deferred session
1446 @param return (tuple): (remaining, results) where: 1446 @param return (tuple): (remaining, results) where:
1447 - remaining is the number of still expected results 1447 - remaining is the number of still expected results
1448 - results is a list of tuple with 1448 - results is a list of tuple with
1449 - service (unicode): pubsub service 1449 - service (unicode): pubsub service
1450 - node (unicode): pubsub node 1450 - node (unicode): pubsub node
1451 - failure (unicode): empty string in case of success, error message else 1451 - failure (unicode): empty string in case of success, error message else
1452 - items_data(list): data as returned by [mbGet] 1452 - items_data(list): data as returned by [mb_get]
1453 - items_metadata(dict): metadata as returned by [mbGet] 1453 - items_metadata(dict): metadata as returned by [mb_get]
1454 @param profile_key: %(doc_profile_key)s 1454 @param profile_key: %(doc_profile_key)s
1455 """ 1455 """
1456 1456
1457 client = self.host.getClient(profile_key) 1457 client = self.host.get_client(profile_key)
1458 1458
1459 def onSuccess(items_data): 1459 def onSuccess(items_data):
1460 """convert items elements to list of microblog data in items_data""" 1460 """convert items elements to list of microblog data in items_data"""
1461 d = self._p.transItemsDataD( 1461 d = self._p.trans_items_data_d(
1462 items_data, 1462 items_data,
1463 # FIXME: service and node should be used here 1463 # FIXME: service and node should be used here
1464 partial(self.item_2_mb_data, client), 1464 partial(self.item_2_mb_data, client),
1465 serialise=True 1465 serialise=True
1466 ) 1466 )
1467 d.addCallback(lambda serialised: ("", serialised)) 1467 d.addCallback(lambda serialised: ("", serialised))
1468 return d 1468 return d
1469 1469
1470 d = self._p.getRTResults( 1470 d = self._p.get_rt_results(
1471 session_id, 1471 session_id,
1472 on_success=onSuccess, 1472 on_success=onSuccess,
1473 on_error=lambda failure: (str(failure.value), ([], {})), 1473 on_error=lambda failure: (str(failure.value), ([], {})),
1474 profile=client.profile, 1474 profile=client.profile,
1475 ) 1475 )
1484 ], 1484 ],
1485 ) 1485 )
1486 ) 1486 )
1487 return d 1487 return d
1488 1488
1489 def _mbGetFromMany(self, publishers_type, publishers, max_items=10, extra_dict=None, 1489 def _mb_get_from_many(self, publishers_type, publishers, max_items=10, extra_dict=None,
1490 profile_key=C.PROF_KEY_NONE): 1490 profile_key=C.PROF_KEY_NONE):
1491 """ 1491 """
1492 @param max_items(int): maximum number of item to get, C.NO_LIMIT for no limit 1492 @param max_items(int): maximum number of item to get, C.NO_LIMIT for no limit
1493 """ 1493 """
1494 max_items = None if max_items == C.NO_LIMIT else max_items 1494 max_items = None if max_items == C.NO_LIMIT else max_items
1495 publishers_type, publishers = self._checkPublishers(publishers_type, publishers) 1495 publishers_type, publishers = self._check_publishers(publishers_type, publishers)
1496 extra = self._p.parseExtra(extra_dict) 1496 extra = self._p.parse_extra(extra_dict)
1497 return self.mbGetFromMany( 1497 return self.mb_get_from_many(
1498 publishers_type, 1498 publishers_type,
1499 publishers, 1499 publishers,
1500 max_items, 1500 max_items,
1501 extra.rsm_request, 1501 extra.rsm_request,
1502 extra.extra, 1502 extra.extra,
1503 profile_key, 1503 profile_key,
1504 ) 1504 )
1505 1505
1506 def mbGetFromMany(self, publishers_type, publishers, max_items=None, rsm_request=None, 1506 def mb_get_from_many(self, publishers_type, publishers, max_items=None, rsm_request=None,
1507 extra=None, profile_key=C.PROF_KEY_NONE): 1507 extra=None, profile_key=C.PROF_KEY_NONE):
1508 """Get the published microblogs for a list of groups or jids 1508 """Get the published microblogs for a list of groups or jids
1509 1509
1510 @param publishers_type (str): type of the list of publishers (one of "GROUP" or 1510 @param publishers_type (str): type of the list of publishers (one of "GROUP" or
1511 "JID" or "ALL") 1511 "JID" or "ALL")
1516 @param extra (dict): Extra data 1516 @param extra (dict): Extra data
1517 @param profile_key: profile key 1517 @param profile_key: profile key
1518 @return (str): RT Deferred session id 1518 @return (str): RT Deferred session id
1519 """ 1519 """
1520 # XXX: extra is unused here so far 1520 # XXX: extra is unused here so far
1521 client, node_data = self._getClientAndNodeData( 1521 client, node_data = self._get_client_and_node_data(
1522 publishers_type, publishers, profile_key 1522 publishers_type, publishers, profile_key
1523 ) 1523 )
1524 return self._p.getFromMany( 1524 return self._p.get_from_many(
1525 node_data, max_items, rsm_request, profile_key=profile_key 1525 node_data, max_items, rsm_request, profile_key=profile_key
1526 ) 1526 )
1527 1527
1528 # comments # 1528 # comments #
1529 1529
1530 def _mbGetFromManyWithCommentsRTResultSerialise(self, data): 1530 def _mb_get_from_many_with_comments_rt_result_serialise(self, data):
1531 """Serialisation of result 1531 """Serialisation of result
1532 1532
1533 This is probably the longest method name of whole SàT ecosystem ^^ 1533 This is probably the longest method name of whole SàT ecosystem ^^
1534 @param data(dict): data as received by rt_sessions 1534 @param data(dict): data as received by rt_sessions
1535 @return (tuple): see [_mbGetFromManyWithCommentsRTResult] 1535 @return (tuple): see [_mb_get_from_many_with_comments_rt_result]
1536 """ 1536 """
1537 ret = [] 1537 ret = []
1538 data_iter = iter(data[1].items()) 1538 data_iter = iter(data[1].items())
1539 for (service, node), (success, (failure_, (items_data, metadata))) in data_iter: 1539 for (service, node), (success, (failure_, (items_data, metadata))) in data_iter:
1540 items = [] 1540 items = []
1548 items, 1548 items,
1549 metadata)) 1549 metadata))
1550 1550
1551 return data[0], ret 1551 return data[0], ret
1552 1552
1553 def _mbGetFromManyWithCommentsRTResult(self, session_id, 1553 def _mb_get_from_many_with_comments_rt_result(self, session_id,
1554 profile_key=C.PROF_KEY_DEFAULT): 1554 profile_key=C.PROF_KEY_DEFAULT):
1555 """Get real-time results for [mbGetFromManyWithComments] session 1555 """Get real-time results for [mb_get_from_many_with_comments] session
1556 1556
1557 @param session_id: id of the real-time deferred session 1557 @param session_id: id of the real-time deferred session
1558 @param return (tuple): (remaining, results) where: 1558 @param return (tuple): (remaining, results) where:
1559 - remaining is the number of still expected results 1559 - remaining is the number of still expected results
1560 - results is a list of 5-tuple with 1560 - results is a list of 5-tuple with
1570 - comments(list[dict]): list of microblog data 1570 - comments(list[dict]): list of microblog data
1571 - comments_metadata(dict): metadata of the comment node 1571 - comments_metadata(dict): metadata of the comment node
1572 - metadata(dict): original node metadata 1572 - metadata(dict): original node metadata
1573 @param profile_key: %(doc_profile_key)s 1573 @param profile_key: %(doc_profile_key)s
1574 """ 1574 """
1575 profile = self.host.getClient(profile_key).profile 1575 profile = self.host.get_client(profile_key).profile
1576 d = self.rt_sessions.getResults(session_id, profile=profile) 1576 d = self.rt_sessions.get_results(session_id, profile=profile)
1577 d.addCallback(self._mbGetFromManyWithCommentsRTResultSerialise) 1577 d.addCallback(self._mb_get_from_many_with_comments_rt_result_serialise)
1578 return d 1578 return d
1579 1579
1580 def _mbGetFromManyWithComments(self, publishers_type, publishers, max_items=10, 1580 def _mb_get_from_many_with_comments(self, publishers_type, publishers, max_items=10,
1581 max_comments=C.NO_LIMIT, extra_dict=None, 1581 max_comments=C.NO_LIMIT, extra_dict=None,
1582 extra_comments_dict=None, profile_key=C.PROF_KEY_NONE): 1582 extra_comments_dict=None, profile_key=C.PROF_KEY_NONE):
1583 """ 1583 """
1584 @param max_items(int): maximum number of item to get, C.NO_LIMIT for no limit 1584 @param max_items(int): maximum number of item to get, C.NO_LIMIT for no limit
1585 @param max_comments(int): maximum number of comments to get, C.NO_LIMIT for no 1585 @param max_comments(int): maximum number of comments to get, C.NO_LIMIT for no
1586 limit 1586 limit
1587 """ 1587 """
1588 max_items = None if max_items == C.NO_LIMIT else max_items 1588 max_items = None if max_items == C.NO_LIMIT else max_items
1589 max_comments = None if max_comments == C.NO_LIMIT else max_comments 1589 max_comments = None if max_comments == C.NO_LIMIT else max_comments
1590 publishers_type, publishers = self._checkPublishers(publishers_type, publishers) 1590 publishers_type, publishers = self._check_publishers(publishers_type, publishers)
1591 extra = self._p.parseExtra(extra_dict) 1591 extra = self._p.parse_extra(extra_dict)
1592 extra_comments = self._p.parseExtra(extra_comments_dict) 1592 extra_comments = self._p.parse_extra(extra_comments_dict)
1593 return self.mbGetFromManyWithComments( 1593 return self.mb_get_from_many_with_comments(
1594 publishers_type, 1594 publishers_type,
1595 publishers, 1595 publishers,
1596 max_items, 1596 max_items,
1597 max_comments or None, 1597 max_comments or None,
1598 extra.rsm_request, 1598 extra.rsm_request,
1600 extra_comments.rsm_request, 1600 extra_comments.rsm_request,
1601 extra_comments.extra, 1601 extra_comments.extra,
1602 profile_key, 1602 profile_key,
1603 ) 1603 )
1604 1604
1605 def mbGetFromManyWithComments(self, publishers_type, publishers, max_items=None, 1605 def mb_get_from_many_with_comments(self, publishers_type, publishers, max_items=None,
1606 max_comments=None, rsm_request=None, extra=None, 1606 max_comments=None, rsm_request=None, extra=None,
1607 rsm_comments=None, extra_comments=None, 1607 rsm_comments=None, extra_comments=None,
1608 profile_key=C.PROF_KEY_NONE): 1608 profile_key=C.PROF_KEY_NONE):
1609 """Helper method to get the microblogs and their comments in one shot 1609 """Helper method to get the microblogs and their comments in one shot
1610 1610
1623 """ 1623 """
1624 # XXX: this method seems complicated because it do a couple of treatments 1624 # XXX: this method seems complicated because it do a couple of treatments
1625 # to serialise and associate the data, but it make life in frontends side 1625 # to serialise and associate the data, but it make life in frontends side
1626 # a lot easier 1626 # a lot easier
1627 1627
1628 client, node_data = self._getClientAndNodeData( 1628 client, node_data = self._get_client_and_node_data(
1629 publishers_type, publishers, profile_key 1629 publishers_type, publishers, profile_key
1630 ) 1630 )
1631 1631
1632 def getComments(items_data): 1632 def get_comments(items_data):
1633 """Retrieve comments and add them to the items_data 1633 """Retrieve comments and add them to the items_data
1634 1634
1635 @param items_data: serialised items data 1635 @param items_data: serialised items data
1636 @return (defer.Deferred): list of items where each item is associated 1636 @return (defer.Deferred): list of items where each item is associated
1637 with a list of comments data (service, node, list of items, metadata) 1637 with a list of comments data (service, node, list of items, metadata)
1647 service_s = value 1647 service_s = value
1648 service = jid.JID(service_s) 1648 service = jid.JID(service_s)
1649 node = item["{}{}".format(prefix, "_node")] 1649 node = item["{}{}".format(prefix, "_node")]
1650 # time to get the comments 1650 # time to get the comments
1651 d = defer.ensureDeferred( 1651 d = defer.ensureDeferred(
1652 self._p.getItems( 1652 self._p.get_items(
1653 client, 1653 client,
1654 service, 1654 service,
1655 node, 1655 node,
1656 max_comments, 1656 max_comments,
1657 rsm_request=rsm_comments, 1657 rsm_request=rsm_comments,
1658 extra=extra_comments, 1658 extra=extra_comments,
1659 ) 1659 )
1660 ) 1660 )
1661 # then serialise 1661 # then serialise
1662 d.addCallback( 1662 d.addCallback(
1663 lambda items_data: self._p.transItemsDataD( 1663 lambda items_data: self._p.trans_items_data_d(
1664 items_data, 1664 items_data,
1665 partial( 1665 partial(
1666 self.item_2_mb_data, client, service=service, node=node 1666 self.item_2_mb_data, client, service=service, node=node
1667 ), 1667 ),
1668 serialise=True 1668 serialise=True
1696 items_d.addCallback(lambda items_completed: (items_completed, metadata)) 1696 items_d.addCallback(lambda items_completed: (items_completed, metadata))
1697 return items_d 1697 return items_d
1698 1698
1699 deferreds = {} 1699 deferreds = {}
1700 for service, node in node_data: 1700 for service, node in node_data:
1701 d = deferreds[(service, node)] = defer.ensureDeferred(self._p.getItems( 1701 d = deferreds[(service, node)] = defer.ensureDeferred(self._p.get_items(
1702 client, service, node, max_items, rsm_request=rsm_request, extra=extra 1702 client, service, node, max_items, rsm_request=rsm_request, extra=extra
1703 )) 1703 ))
1704 d.addCallback( 1704 d.addCallback(
1705 lambda items_data: self._p.transItemsDataD( 1705 lambda items_data: self._p.trans_items_data_d(
1706 items_data, 1706 items_data,
1707 partial(self.item_2_mb_data, client, service=service, node=node), 1707 partial(self.item_2_mb_data, client, service=service, node=node),
1708 ) 1708 )
1709 ) 1709 )
1710 d.addCallback(getComments) 1710 d.addCallback(get_comments)
1711 d.addCallback(lambda items_comments_data: ("", items_comments_data)) 1711 d.addCallback(lambda items_comments_data: ("", items_comments_data))
1712 d.addErrback(lambda failure: (str(failure.value), ([], {}))) 1712 d.addErrback(lambda failure: (str(failure.value), ([], {})))
1713 1713
1714 return self.rt_sessions.newSession(deferreds, client.profile) 1714 return self.rt_sessions.new_session(deferreds, client.profile)
1715 1715
1716 1716
1717 @implementer(iwokkel.IDisco) 1717 @implementer(iwokkel.IDisco)
1718 class XEP_0277_handler(XMPPHandler): 1718 class XEP_0277_handler(XMPPHandler):
1719 1719