comparison src/plugins/plugin_xep_0277.py @ 1419:be2df1ddea8e

plugins (groupblog, xep-0277) + tmp(rsm): improved style: - removed external parenthesis in assertions - added blank line after first line of docstrings - replaced "__" prefixes by "_" - renamed variabled named after the reserverd word "max" to "max_"
author Goffi <goffi@goffi.org>
date Wed, 22 Apr 2015 18:30:28 +0200
parents 3265a2639182
children 16b1ba7ccaaa
comparison
equal deleted inserted replaced
1418:6adf1b0be609 1419:be2df1ddea8e
93 if not node: 93 if not node:
94 raise exceptions.DataError('Invalid comments link') 94 raise exceptions.DataError('Invalid comments link')
95 95
96 return (service, node) 96 return (service, node)
97 97
98 def __removeXHTMLMarkups(self, xhtml): 98 def _removeXHTMLMarkups(self, xhtml):
99 """ 99 """Remove XHTML markups from the given string.
100 Remove XHTML markups from the given string. 100
101 @param xhtml: the XHTML string to be cleaned 101 @param xhtml: the XHTML string to be cleaned
102 @return: a Deferred instance for the cleaned string 102 @return: a Deferred instance for the cleaned string
103 """ 103 """
104 return self.host.plugins["TEXT-SYNTAXES"].convert(xhtml, 104 return self.host.plugins["TEXT-SYNTAXES"].convert(xhtml,
105 self.host.plugins["TEXT-SYNTAXES"].SYNTAX_XHTML, 105 self.host.plugins["TEXT-SYNTAXES"].SYNTAX_XHTML,
140 140
141 microblog_data = {} 141 microblog_data = {}
142 142
143 for key in ['title', 'content']: # process the textual elements 143 for key in ['title', 'content']: # process the textual elements
144 for attr_elt in xpath(entry_elt, key): 144 for attr_elt in xpath(entry_elt, key):
145 attr_content = self.__getLXMLInnerContent(attr_elt) 145 attr_content = self._getLXMLInnerContent(attr_elt)
146 if not attr_content.strip(): 146 if not attr_content.strip():
147 continue # element with empty value 147 continue # element with empty value
148 content_type = attr_elt.get('type', 'text').lower() 148 content_type = attr_elt.get('type', 'text').lower()
149 if content_type == 'xhtml': 149 if content_type == 'xhtml':
150 text = self.__decapsulateExtraNS(attr_content) 150 text = self._decapsulateExtraNS(attr_content)
151 microblog_data['%s_xhtml' % key] = yield self.host.plugins["TEXT-SYNTAXES"].clean_xhtml(text) 151 microblog_data['%s_xhtml' % key] = yield self.host.plugins["TEXT-SYNTAXES"].clean_xhtml(text)
152 else: 152 else:
153 microblog_data[key] = attr_content 153 microblog_data[key] = attr_content
154 if key not in microblog_data and ('%s_xhtml' % key) in microblog_data: 154 if key not in microblog_data and ('%s_xhtml' % key) in microblog_data:
155 microblog_data[key] = yield self.__removeXHTMLMarkups(microblog_data['%s_xhtml' % key]) 155 microblog_data[key] = yield self._removeXHTMLMarkups(microblog_data['%s_xhtml' % key])
156 156
157 try: # check for mandatory elements 157 try: # check for mandatory elements
158 microblog_data['id'] = xpath(entry_elt, 'id')[0].text 158 microblog_data['id'] = xpath(entry_elt, 'id')[0].text
159 microblog_data['updated'] = date2float(entry_elt, 'updated') 159 microblog_data['updated'] = date2float(entry_elt, 'updated')
160 assert('title' in microblog_data) # has been processed already 160 assert('title' in microblog_data) # has been processed already
196 except IndexError: 196 except IndexError:
197 log.warning(_(u"Can't find author element in atom entry %s") % microblog_data['id']) 197 log.warning(_(u"Can't find author element in atom entry %s") % microblog_data['id'])
198 198
199 defer.returnValue(microblog_data) 199 defer.returnValue(microblog_data)
200 200
201 def __getLXMLInnerContent(self, elt): 201 def _getLXMLInnerContent(self, elt):
202 """Return the inner content of a lxml.etree.Element. It is not 202 """Return the inner content of a lxml.etree.Element. It is not
203 trivial because the lxml tostring method would return the full 203 trivial because the lxml tostring method would return the full
204 content including elt's tag and attributes, and elt.getchildren() 204 content including elt's tag and attributes, and elt.getchildren()
205 would skip a text value which is not within an element...""" 205 would skip a text value which is not within an element..."""
206 return self.__getDomishInnerContent(ElementParser()(etree.tostring(elt))) 206 return self._getDomishInnerContent(ElementParser()(etree.tostring(elt)))
207 207
208 def __getDomishInnerContent(self, elt): 208 def _getDomishInnerContent(self, elt):
209 """Return the inner content of a domish.Element.""" 209 """Return the inner content of a domish.Element."""
210 result = '' 210 result = ''
211 for child in elt.children: 211 for child in elt.children:
212 try: 212 try:
213 result += child.toXml() # child id a domish.Element 213 result += child.toXml() # child id a domish.Element
214 except AttributeError: 214 except AttributeError:
215 result += child # child is unicode 215 result += child # child is unicode
216 return result 216 return result
217 217
218 def __decapsulateExtraNS(self, text): 218 def _decapsulateExtraNS(self, text):
219 """Check for XHTML namespace and decapsulate the content so the user 219 """Check for XHTML namespace and decapsulate the content so the user
220 who wants to modify an entry will see the text that he entered. Also 220 who wants to modify an entry will see the text that he entered. Also
221 this avoids successive encapsulation with a new <div>...</div> at 221 this avoids successive encapsulation with a new <div>...</div> at
222 each modification (encapsulation is done in self.data2entry)""" 222 each modification (encapsulation is done in self.data2entry)"""
223 elt = ElementParser()(text) 223 elt = ElementParser()(text)
224 if elt.uri != NS_XHTML: 224 if elt.uri != NS_XHTML:
225 raise exceptions.DataError(_('Content of type XHTML must declare its namespace!')) 225 raise exceptions.DataError(_('Content of type XHTML must declare its namespace!'))
226 return self.__getDomishInnerContent(elt) 226 return self._getDomishInnerContent(elt)
227 227
228 def microblogCB(self, itemsEvent, profile): 228 def microblogCB(self, itemsEvent, profile):
229 """Callback to "MICROBLOG" PEP event.""" 229 """Callback to "MICROBLOG" PEP event."""
230 def manageItem(microblog_data): 230 def manageItem(microblog_data):
231 self.host.bridge.personalEvent(itemsEvent.sender.full(), "MICROBLOG", microblog_data, profile) 231 self.host.bridge.personalEvent(itemsEvent.sender.full(), "MICROBLOG", microblog_data, profile)
234 self.item2mbdata(item).addCallbacks(manageItem, lambda failure: None) 234 self.item2mbdata(item).addCallbacks(manageItem, lambda failure: None)
235 235
236 @defer.inlineCallbacks 236 @defer.inlineCallbacks
237 def data2entry(self, data, profile): 237 def data2entry(self, data, profile):
238 """Convert a data dict to en entry usable to create an item 238 """Convert a data dict to en entry usable to create an item
239
239 @param data: data dict as given by bridge method. 240 @param data: data dict as given by bridge method.
240 @return: deferred which fire domish.Element""" 241 @return: deferred which fire domish.Element
242 """
241 _uuid = unicode(uuid.uuid1()) 243 _uuid = unicode(uuid.uuid1())
242 _entry = atom.Entry() 244 _entry = atom.Entry()
243 _entry.title = '' # reset the default value which is not empty 245 _entry.title = '' # reset the default value which is not empty
244 246
245 elems = {'title': atom.Title, 'content': atom.Content} 247 elems = {'title': atom.Title, 'content': atom.Content}
264 elem = elems[key](escape(data[attr]).encode('utf-8')) 266 elem = elems[key](escape(data[attr]).encode('utf-8'))
265 elem.attrs['type'] = 'text' 267 elem.attrs['type'] = 'text'
266 setattr(_entry, key, elem) 268 setattr(_entry, key, elem)
267 if not getattr(_entry, key).text: 269 if not getattr(_entry, key).text:
268 if hasattr(_entry, '%s_xhtml' % key): 270 if hasattr(_entry, '%s_xhtml' % key):
269 text = yield self.__removeXHTMLMarkups(getattr(_entry, '%s_xhtml' % key).text) 271 text = yield self._removeXHTMLMarkups(getattr(_entry, '%s_xhtml' % key).text)
270 setattr(_entry, key, text) 272 setattr(_entry, key, text)
271 if not _entry.title.text: # eventually move the data from content to title 273 if not _entry.title.text: # eventually move the data from content to title
272 _entry.title = _entry.content.text 274 _entry.title = _entry.content.text
273 _entry.title.attrs['type'] = _entry.content.attrs['type'] 275 _entry.title.attrs['type'] = _entry.content.attrs['type']
274 _entry.content.text = '' 276 _entry.content.text = ''
296 defer.returnValue(item) 298 defer.returnValue(item)
297 299
298 @defer.inlineCallbacks 300 @defer.inlineCallbacks
299 def sendMicroblog(self, data, profile): 301 def sendMicroblog(self, data, profile):
300 """Send XEP-0277's microblog data 302 """Send XEP-0277's microblog data
303
301 @param data: must include content 304 @param data: must include content
302 @param profile: profile which send the mood""" 305 @param profile: profile which send the mood"""
303 if 'content' not in data: 306 if 'content' not in data:
304 log.error(_("Microblog data must contain at least 'content' key")) 307 log.error(_("Microblog data must contain at least 'content' key"))
305 raise exceptions.DataError('no "content" key found') 308 raise exceptions.DataError('no "content" key found')
311 ret = yield self.host.plugins["XEP-0060"].publish(None, NS_MICROBLOG, [item], profile_key=profile) 314 ret = yield self.host.plugins["XEP-0060"].publish(None, NS_MICROBLOG, [item], profile_key=profile)
312 defer.returnValue(ret) 315 defer.returnValue(ret)
313 316
314 def getLastMicroblogs(self, pub_jid, max_items=10, profile_key=C.PROF_KEY_NONE): 317 def getLastMicroblogs(self, pub_jid, max_items=10, profile_key=C.PROF_KEY_NONE):
315 """Get the last published microblogs 318 """Get the last published microblogs
319
316 @param pub_jid: jid of the publisher 320 @param pub_jid: jid of the publisher
317 @param max_items: how many microblogs we want to get 321 @param max_items: how many microblogs we want to get
318 @param profile_key: profile key 322 @param profile_key: profile key
319 323
320 @return: a deferred couple with the list of items and RSM information. 324 @return: a deferred couple with the list of items and RSM information.
324 d.addCallback(lambda res: ([value for (success, value) in res[0] if success], res[1])) 328 d.addCallback(lambda res: ([value for (success, value) in res[0] if success], res[1]))
325 return d 329 return d
326 330
327 def setMicroblogAccess(self, access="presence", profile_key=C.PROF_KEY_NONE): 331 def setMicroblogAccess(self, access="presence", profile_key=C.PROF_KEY_NONE):
328 """Create a microblog node on PEP with given access 332 """Create a microblog node on PEP with given access
333
329 If the node already exists, it change options 334 If the node already exists, it change options
330 @param access: Node access model, according to xep-0060 #4.5 335 @param access: Node access model, according to xep-0060 #4.5
331 @param profile_key: profile key""" 336 @param profile_key: profile key"""
332 337
333 _jid, xmlstream = self.host.getJidNStream(profile_key) 338 _jid, xmlstream = self.host.getJidNStream(profile_key)