Mercurial > libervia-backend
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 |