Mercurial > libervia-backend
comparison sat_frontends/quick_frontend/quick_blog.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 26edcf3a30eb |
children | 003b8b4b56a7 |
comparison
equal
deleted
inserted
replaced
2623:49533de4540b | 2624:56f94936df1e |
---|---|
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 # from sat.core.i18n import _, D_ | 20 # from sat.core.i18n import _, D_ |
21 from sat.core.log import getLogger | 21 from sat.core.log import getLogger |
22 | |
22 log = getLogger(__name__) | 23 log = getLogger(__name__) |
23 | 24 |
24 | 25 |
25 from sat_frontends.quick_frontend.constants import Const as C | 26 from sat_frontends.quick_frontend.constants import Const as C |
26 from sat_frontends.quick_frontend import quick_widgets | 27 from sat_frontends.quick_frontend import quick_widgets |
27 from sat_frontends.tools import jid | 28 from sat_frontends.tools import jid |
28 from sat.tools.common import data_format | 29 from sat.tools.common import data_format |
29 | 30 |
30 try: | 31 try: |
31 # FIXME: to be removed when an acceptable solution is here | 32 # FIXME: to be removed when an acceptable solution is here |
32 unicode('') # XXX: unicode doesn't exist in pyjamas | 33 unicode("") # XXX: unicode doesn't exist in pyjamas |
33 except (TypeError, AttributeError): # Error raised is not the same depending on pyjsbuild options | 34 except ( |
35 TypeError, | |
36 AttributeError, | |
37 ): # Error raised is not the same depending on pyjsbuild options | |
34 unicode = str | 38 unicode = str |
35 | 39 |
36 ENTRY_CLS = None | 40 ENTRY_CLS = None |
37 COMMENTS_CLS = None | 41 COMMENTS_CLS = None |
38 | 42 |
43 def __init__(self, data): | 47 def __init__(self, data): |
44 """ | 48 """ |
45 @param data(dict): microblog data as return by bridge methods | 49 @param data(dict): microblog data as return by bridge methods |
46 if data values are not defined, set default values | 50 if data values are not defined, set default values |
47 """ | 51 """ |
48 self.id = data['id'] | 52 self.id = data["id"] |
49 self.title = data.get('title') | 53 self.title = data.get("title") |
50 self.title_rich = None | 54 self.title_rich = None |
51 self.title_xhtml = data.get('title_xhtml') | 55 self.title_xhtml = data.get("title_xhtml") |
52 self.tags = list(data_format.dict2iter('tag', data)) | 56 self.tags = list(data_format.dict2iter("tag", data)) |
53 self.content = data.get('content') | 57 self.content = data.get("content") |
54 self.content_rich = None | 58 self.content_rich = None |
55 self.content_xhtml = data.get('content_xhtml') | 59 self.content_xhtml = data.get("content_xhtml") |
56 self.author = data['author'] | 60 self.author = data["author"] |
57 try: | 61 try: |
58 author_jid = data['author_jid'] | 62 author_jid = data["author_jid"] |
59 self.author_jid = jid.JID(author_jid) if author_jid else None | 63 self.author_jid = jid.JID(author_jid) if author_jid else None |
60 except KeyError: | 64 except KeyError: |
61 self.author_jid = None | 65 self.author_jid = None |
62 | 66 |
63 try: | 67 try: |
64 self.author_verified = C.bool(data['author_jid_verified']) | 68 self.author_verified = C.bool(data["author_jid_verified"]) |
65 except KeyError: | 69 except KeyError: |
66 self.author_verified = False | 70 self.author_verified = False |
67 | 71 |
68 try: | 72 try: |
69 self.updated = float(data['updated']) # XXX: int doesn't work here (pyjamas bug) | 73 self.updated = float( |
74 data["updated"] | |
75 ) # XXX: int doesn't work here (pyjamas bug) | |
70 except KeyError: | 76 except KeyError: |
71 self.updated = None | 77 self.updated = None |
72 | 78 |
73 try: | 79 try: |
74 self.published = float(data['published']) # XXX: int doesn't work here (pyjamas bug) | 80 self.published = float( |
81 data["published"] | |
82 ) # XXX: int doesn't work here (pyjamas bug) | |
75 except KeyError: | 83 except KeyError: |
76 self.published = None | 84 self.published = None |
77 | 85 |
78 self.comments = data.get('comments') | 86 self.comments = data.get("comments") |
79 try: | 87 try: |
80 self.comments_service = jid.JID(data['comments_service']) | 88 self.comments_service = jid.JID(data["comments_service"]) |
81 except KeyError: | 89 except KeyError: |
82 self.comments_service = None | 90 self.comments_service = None |
83 self.comments_node = data.get('comments_node') | 91 self.comments_node = data.get("comments_node") |
84 | 92 |
85 # def loadComments(self): | 93 # def loadComments(self): |
86 # """Load all the comments""" | 94 # """Load all the comments""" |
87 # index = str(main_entry.comments_count - main_entry.hidden_count) | 95 # index = str(main_entry.comments_count - main_entry.hidden_count) |
88 # rsm = {'max': str(main_entry.hidden_count), 'index': index} | 96 # rsm = {'max': str(main_entry.hidden_count), 'index': index} |
138 """ | 146 """ |
139 items, metadata = items_tuple | 147 items, metadata = items_tuple |
140 for item, comments in items: | 148 for item, comments in items: |
141 self.addEntry(item, comments, service=service, node=node, with_update=False) | 149 self.addEntry(item, comments, service=service, node=node, with_update=False) |
142 | 150 |
143 def addEntry(self, item=None, comments=None, service=None, node=None, with_update=True, editable=False, edit_entry=False): | 151 def addEntry( |
152 self, | |
153 item=None, | |
154 comments=None, | |
155 service=None, | |
156 node=None, | |
157 with_update=True, | |
158 editable=False, | |
159 edit_entry=False, | |
160 ): | |
144 """Add a microblog entry | 161 """Add a microblog entry |
145 | 162 |
146 @param editable (bool): True if the entry can be modified | 163 @param editable (bool): True if the entry can be modified |
147 @param item (dict, None): blog item data, or None for an empty entry | 164 @param item (dict, None): blog item data, or None for an empty entry |
148 @param comments (list, None): list of comments data if available | 165 @param comments (list, None): list of comments data if available |
176 | 193 |
177 class Entry(EntriesManager): | 194 class Entry(EntriesManager): |
178 """Graphical representation of an Item | 195 """Graphical representation of an Item |
179 This class must be overriden by frontends""" | 196 This class must be overriden by frontends""" |
180 | 197 |
181 def __init__(self, manager, item_data=None, comments_data=None, service=None, node=None): | 198 def __init__( |
199 self, manager, item_data=None, comments_data=None, service=None, node=None | |
200 ): | |
182 """ | 201 """ |
183 @param blog(QuickBlog): the parent QuickBlog | 202 @param blog(QuickBlog): the parent QuickBlog |
184 @param manager(EntriesManager): the parent EntriesManager | 203 @param manager(EntriesManager): the parent EntriesManager |
185 @param item_data(dict, None): dict containing the blog item data, or None for an empty entry | 204 @param item_data(dict, None): dict containing the blog item data, or None for an empty entry |
186 @param comments_data(list, None): list of comments data | 205 @param comments_data(list, None): list of comments data |
192 self.editable = False | 211 self.editable = False |
193 self.reset(item_data) | 212 self.reset(item_data) |
194 self.blog.id2entries[self.item.id] = self | 213 self.blog.id2entries[self.item.id] = self |
195 if self.item.comments: | 214 if self.item.comments: |
196 node_tuple = (self.item.comments_service, self.item.comments_node) | 215 node_tuple = (self.item.comments_service, self.item.comments_node) |
197 self.blog.node2entries.setdefault(node_tuple,[]).append(self) | 216 self.blog.node2entries.setdefault(node_tuple, []).append(self) |
198 | 217 |
199 def reset(self, item_data): | 218 def reset(self, item_data): |
200 """Reset the entry with given data | 219 """Reset the entry with given data |
201 | 220 |
202 used during init (it's a set and not a reset then) | 221 used during init (it's a set and not a reset then) |
203 or later (e.g. message sent, or cancellation of an edition | 222 or later (e.g. message sent, or cancellation of an edition |
204 @param idem_data(dict, None): data as in __init__ | 223 @param idem_data(dict, None): data as in __init__ |
205 """ | 224 """ |
206 if item_data is None: | 225 if item_data is None: |
207 self.new = True | 226 self.new = True |
208 item_data = {'id': None, | 227 item_data = { |
209 # TODO: find a best author value | 228 "id": None, |
210 'author': self.blog.host.whoami.node | 229 # TODO: find a best author value |
211 } | 230 "author": self.blog.host.whoami.node, |
231 } | |
212 else: | 232 else: |
213 self.new = False | 233 self.new = False |
214 self.item = Item(item_data) | 234 self.item = Item(item_data) |
215 self.author_jid = self.blog.host.whoami.bare if self.new else self.item.author_jid | 235 self.author_jid = self.blog.host.whoami.bare if self.new else self.item.author_jid |
216 if self.author_jid is None and self.service and self.service.node: | 236 if self.author_jid is None and self.service and self.service.node: |
217 self.author_jid = self.service | 237 self.author_jid = self.service |
218 self.mode = C.ENTRY_MODE_TEXT if self.item.content_xhtml is None else C.ENTRY_MODE_XHTML | 238 self.mode = ( |
239 C.ENTRY_MODE_TEXT if self.item.content_xhtml is None else C.ENTRY_MODE_XHTML | |
240 ) | |
219 | 241 |
220 def refresh(self): | 242 def refresh(self): |
221 """Refresh the display when data have been modified""" | 243 """Refresh the display when data have been modified""" |
222 pass | 244 pass |
223 | 245 |
224 def setEditable(self, editable=True): | 246 def setEditable(self, editable=True): |
225 """tell if the entry can be edited or not | 247 """tell if the entry can be edited or not |
226 | 248 |
227 @param editable(bool): True if the entry can be edited | 249 @param editable(bool): True if the entry can be edited |
228 """ | 250 """ |
229 #XXX: we don't use @property as property setter doesn't play well with pyjamas | 251 # XXX: we don't use @property as property setter doesn't play well with pyjamas |
230 raise NotImplementedError | 252 raise NotImplementedError |
231 | 253 |
232 def addComments(self, comments_data): | 254 def addComments(self, comments_data): |
233 """Add comments to this entry by calling addEntry repeatidly | 255 """Add comments to this entry by calling addEntry repeatidly |
234 | 256 |
247 def send(self): | 269 def send(self): |
248 """Send entry according to parent QuickBlog configuration and current level""" | 270 """Send entry according to parent QuickBlog configuration and current level""" |
249 | 271 |
250 # keys to keep other than content*, title* and tag* | 272 # keys to keep other than content*, title* and tag* |
251 # FIXME: see how to avoid comments node hijacking (someone could bind his post to another post's comments node) | 273 # FIXME: see how to avoid comments node hijacking (someone could bind his post to another post's comments node) |
252 keys_to_keep = ('id', 'comments', 'author', 'author_jid', 'published') | 274 keys_to_keep = ("id", "comments", "author", "author_jid", "published") |
253 | 275 |
254 mb_data = {} | 276 mb_data = {} |
255 for key in keys_to_keep: | 277 for key in keys_to_keep: |
256 value = getattr(self.item, key) | 278 value = getattr(self.item, key) |
257 if value is not None: | 279 if value is not None: |
258 mb_data[key] = unicode(value) | 280 mb_data[key] = unicode(value) |
259 | 281 |
260 for prefix in ('content', 'title'): | 282 for prefix in ("content", "title"): |
261 for suffix in ('', '_rich', '_xhtml'): | 283 for suffix in ("", "_rich", "_xhtml"): |
262 name = '{}{}'.format(prefix, suffix) | 284 name = "{}{}".format(prefix, suffix) |
263 value = getattr(self.item, name) | 285 value = getattr(self.item, name) |
264 if value is not None: | 286 if value is not None: |
265 mb_data[name] = value | 287 mb_data[name] = value |
266 | 288 |
267 data_format.iter2dict('tag', self.item.tags, mb_data) | 289 data_format.iter2dict("tag", self.item.tags, mb_data) |
268 | 290 |
269 if self.blog.new_message_target not in (C.PUBLIC, C.GROUP): | 291 if self.blog.new_message_target not in (C.PUBLIC, C.GROUP): |
270 raise NotImplementedError | 292 raise NotImplementedError |
271 | 293 |
272 if self.level == 0: | 294 if self.level == 0: |
273 mb_data["allow_comments"] = C.BOOL_TRUE | 295 mb_data["allow_comments"] = C.BOOL_TRUE |
274 | 296 |
275 if self.blog.new_message_target == C.GROUP: | 297 if self.blog.new_message_target == C.GROUP: |
276 data_format.iter2dict('group', self.blog.targets, mb_data) | 298 data_format.iter2dict("group", self.blog.targets, mb_data) |
277 | 299 |
278 self.blog.host.bridge.mbSend( | 300 self.blog.host.bridge.mbSend( |
279 unicode(self.service or ''), | 301 unicode(self.service or ""), |
280 self.node or '', | 302 self.node or "", |
281 mb_data, | 303 mb_data, |
282 profile=self.blog.profile) | 304 profile=self.blog.profile, |
305 ) | |
283 | 306 |
284 def delete(self): | 307 def delete(self): |
285 """Remove this Entry from parent manager | 308 """Remove this Entry from parent manager |
286 | 309 |
287 This doesn't delete any entry in PubSub, just locally | 310 This doesn't delete any entry in PubSub, just locally |
288 all children entries will be recursively removed too | 311 all children entries will be recursively removed too |
289 """ | 312 """ |
290 # XXX: named delete and not remove to avoid conflict with pyjamas | 313 # XXX: named delete and not remove to avoid conflict with pyjamas |
291 log.debug(u"deleting entry {}".format('EDIT ENTRY' if self.new else self.item.id)) | 314 log.debug(u"deleting entry {}".format("EDIT ENTRY" if self.new else self.item.id)) |
292 for child in self.entries: | 315 for child in self.entries: |
293 child.delete() | 316 child.delete() |
294 try: | 317 try: |
295 self.manager.entries.remove(self) | 318 self.manager.entries.remove(self) |
296 except ValueError: | 319 except ValueError: |
301 if not self.new: | 324 if not self.new: |
302 # we must remove references to self | 325 # we must remove references to self |
303 # in QuickBlog's dictionary | 326 # in QuickBlog's dictionary |
304 del self.blog.id2entries[self.item.id] | 327 del self.blog.id2entries[self.item.id] |
305 if self.item.comments: | 328 if self.item.comments: |
306 comments_tuple = (self.item.comments_service, | 329 comments_tuple = (self.item.comments_service, self.item.comments_node) |
307 self.item.comments_node) | |
308 other_entries = self.blog.node2entries[comments_tuple].remove(self) | 330 other_entries = self.blog.node2entries[comments_tuple].remove(self) |
309 if not other_entries: | 331 if not other_entries: |
310 del self.blog.node2entries[comments_tuple] | 332 del self.blog.node2entries[comments_tuple] |
311 | 333 |
312 def retract(self): | 334 def retract(self): |
314 | 336 |
315 if there is a comments node, it will be purged too | 337 if there is a comments node, it will be purged too |
316 """ | 338 """ |
317 # TODO: manage several comments nodes case. | 339 # TODO: manage several comments nodes case. |
318 if self.item.comments: | 340 if self.item.comments: |
319 self.blog.host.bridge.psNodeDelete(unicode(self.item.comments_service) or "", self.item.comments_node, profile=self.blog.profile) | 341 self.blog.host.bridge.psNodeDelete( |
320 self.blog.host.bridge.mbRetract(unicode(self.service or ""), self.node or "", self.item.id, profile=self.blog.profile) | 342 unicode(self.item.comments_service) or "", |
343 self.item.comments_node, | |
344 profile=self.blog.profile, | |
345 ) | |
346 self.blog.host.bridge.mbRetract( | |
347 unicode(self.service or ""), | |
348 self.node or "", | |
349 self.item.id, | |
350 profile=self.blog.profile, | |
351 ) | |
321 | 352 |
322 | 353 |
323 class QuickBlog(EntriesManager, quick_widgets.QuickWidget): | 354 class QuickBlog(EntriesManager, quick_widgets.QuickWidget): |
324 | |
325 def __init__(self, host, targets, profiles=None): | 355 def __init__(self, host, targets, profiles=None): |
326 """Panel used to show microblog | 356 """Panel used to show microblog |
327 | 357 |
328 @param targets (tuple(unicode)): contact groups displayed in this panel. | 358 @param targets (tuple(unicode)): contact groups displayed in this panel. |
329 If empty, show all microblogs from all contacts. targets is also used | 359 If empty, show all microblogs from all contacts. targets is also used |
330 to know where to send new messages. | 360 to know where to send new messages. |
331 """ | 361 """ |
332 EntriesManager.__init__(self, None) | 362 EntriesManager.__init__(self, None) |
333 self.id2entries = {} # used to find an entry with it's item id | 363 self.id2entries = {} # used to find an entry with it's item id |
334 # must be kept up-to-date by Entry | 364 # must be kept up-to-date by Entry |
335 self.node2entries = {} # same as above, values are lists in case of | 365 self.node2entries = {} # same as above, values are lists in case of |
336 # two entries link to the same comments node | 366 # two entries link to the same comments node |
337 if not targets: | 367 if not targets: |
338 targets = () # XXX: we use empty tuple instead of None to workaround a pyjamas bug | 368 targets = () # XXX: we use empty tuple instead of None to workaround a pyjamas bug |
339 quick_widgets.QuickWidget.__init__(self, host, targets, C.PROF_KEY_NONE) | 369 quick_widgets.QuickWidget.__init__(self, host, targets, C.PROF_KEY_NONE) |
340 self._targets_type = C.ALL | 370 self._targets_type = C.ALL |
341 else: | 371 else: |
342 assert isinstance(targets[0], basestring) | 372 assert isinstance(targets[0], basestring) |
343 quick_widgets.QuickWidget.__init__(self, host, targets[0], C.PROF_KEY_NONE) | 373 quick_widgets.QuickWidget.__init__(self, host, targets[0], C.PROF_KEY_NONE) |
354 return C.GROUP | 384 return C.GROUP |
355 else: | 385 else: |
356 raise ValueError("Unkown targets type") | 386 raise ValueError("Unkown targets type") |
357 | 387 |
358 def __str__(self): | 388 def __str__(self): |
359 return u"Blog Widget [target: {}, profile: {}]".format(', '.join(self.targets), self.profile) | 389 return u"Blog Widget [target: {}, profile: {}]".format( |
390 ", ".join(self.targets), self.profile | |
391 ) | |
360 | 392 |
361 def _getResultsCb(self, data, rt_session): | 393 def _getResultsCb(self, data, rt_session): |
362 remaining, results = data | 394 remaining, results = data |
363 log.debug("Got {got_len} results, {rem_len} remaining".format(got_len=len(results), rem_len=remaining)) | 395 log.debug( |
396 "Got {got_len} results, {rem_len} remaining".format( | |
397 got_len=len(results), rem_len=remaining | |
398 ) | |
399 ) | |
364 for result in results: | 400 for result in results: |
365 service, node, failure, items, metadata = result | 401 service, node, failure, items, metadata = result |
366 if not failure: | 402 if not failure: |
367 self._addMBItemsWithComments((items, metadata), service=jid.JID(service)) | 403 self._addMBItemsWithComments((items, metadata), service=jid.JID(service)) |
368 | 404 |
376 def _getResults(self, rt_session): | 412 def _getResults(self, rt_session): |
377 """Manage results from mbGetFromMany RT Session | 413 """Manage results from mbGetFromMany RT Session |
378 | 414 |
379 @param rt_session(str): session id as returned by mbGetFromMany | 415 @param rt_session(str): session id as returned by mbGetFromMany |
380 """ | 416 """ |
381 self.host.bridge.mbGetFromManyWithCommentsRTResult(rt_session, profile=self.profile, | 417 self.host.bridge.mbGetFromManyWithCommentsRTResult( |
382 callback=lambda data:self._getResultsCb(data, rt_session), | 418 rt_session, |
383 errback=self._getResultsEb) | 419 profile=self.profile, |
420 callback=lambda data: self._getResultsCb(data, rt_session), | |
421 errback=self._getResultsEb, | |
422 ) | |
384 | 423 |
385 def getAll(self): | 424 def getAll(self): |
386 """Get all (micro)blogs from self.targets""" | 425 """Get all (micro)blogs from self.targets""" |
426 | |
387 def gotSession(rt_session): | 427 def gotSession(rt_session): |
388 self._getResults(rt_session) | 428 self._getResults(rt_session) |
389 | 429 |
390 if self._targets_type in (C.ALL, C.GROUP): | 430 if self._targets_type in (C.ALL, C.GROUP): |
391 targets = tuple(self.targets) if self._targets_type is C.GROUP else () | 431 targets = tuple(self.targets) if self._targets_type is C.GROUP else () |
392 self.host.bridge.mbGetFromManyWithComments(self._targets_type, targets, 10, 10, {}, {"subscribe":C.BOOL_TRUE}, profile=self.profile, callback=gotSession) | 432 self.host.bridge.mbGetFromManyWithComments( |
433 self._targets_type, | |
434 targets, | |
435 10, | |
436 10, | |
437 {}, | |
438 {"subscribe": C.BOOL_TRUE}, | |
439 profile=self.profile, | |
440 callback=gotSession, | |
441 ) | |
393 own_pep = self.host.whoami.bare | 442 own_pep = self.host.whoami.bare |
394 self.host.bridge.mbGetFromManyWithComments(C.JID, (unicode(own_pep),), 10, 10, {}, {}, profile=self.profile, callback=gotSession) | 443 self.host.bridge.mbGetFromManyWithComments( |
395 else: | 444 C.JID, |
396 raise NotImplementedError(u'{} target type is not managed'.format(self._targets_type)) | 445 (unicode(own_pep),), |
446 10, | |
447 10, | |
448 {}, | |
449 {}, | |
450 profile=self.profile, | |
451 callback=gotSession, | |
452 ) | |
453 else: | |
454 raise NotImplementedError( | |
455 u"{} target type is not managed".format(self._targets_type) | |
456 ) | |
397 | 457 |
398 def isJidAccepted(self, jid_): | 458 def isJidAccepted(self, jid_): |
399 """Tell if a jid is actepted and must be shown in this panel | 459 """Tell if a jid is actepted and must be shown in this panel |
400 | 460 |
401 @param jid_(jid.JID): jid to check | 461 @param jid_(jid.JID): jid to check |
402 @return: True if the jid is accepted | 462 @return: True if the jid is accepted |
403 """ | 463 """ |
404 if self._targets_type == C.ALL: | 464 if self._targets_type == C.ALL: |
405 return True | 465 return True |
406 assert self._targets_type is C.GROUP # we don't manage other types for now | 466 assert self._targets_type is C.GROUP # we don't manage other types for now |
407 for group in self.targets: | 467 for group in self.targets: |
408 if self.host.contact_lists[self.profile].isEntityInGroup(jid_, group): | 468 if self.host.contact_lists[self.profile].isEntityInGroup(jid_, group): |
409 return True | 469 return True |
410 return False | 470 return False |
411 | 471 |
420 @param groups(list[unicode], None): groups which can receive this entry | 480 @param groups(list[unicode], None): groups which can receive this entry |
421 None to accept everything | 481 None to accept everything |
422 @param profile: %(doc_profile)s | 482 @param profile: %(doc_profile)s |
423 """ | 483 """ |
424 try: | 484 try: |
425 entry = self.id2entries[mb_data['id']] | 485 entry = self.id2entries[mb_data["id"]] |
426 except KeyError: | 486 except KeyError: |
427 # The entry is new | 487 # The entry is new |
428 try: | 488 try: |
429 parent_entries = self.node2entries[(service, node)] | 489 parent_entries = self.node2entries[(service, node)] |
430 except: | 490 except: |
431 # The node is unknown, | 491 # The node is unknown, |
432 # we need to check that we can accept the entry | 492 # we need to check that we can accept the entry |
433 if (self.isJidAccepted(service) | 493 if ( |
434 or (groups is None and service == self.host.profiles[self.profile].whoami.bare) | 494 self.isJidAccepted(service) |
435 or (groups and groups.intersection(self.targets))): | 495 or ( |
496 groups is None | |
497 and service == self.host.profiles[self.profile].whoami.bare | |
498 ) | |
499 or (groups and groups.intersection(self.targets)) | |
500 ): | |
436 self.addEntry(mb_data, service=service, node=node) | 501 self.addEntry(mb_data, service=service, node=node) |
437 else: | 502 else: |
438 # the entry is a comment in a known node | 503 # the entry is a comment in a known node |
439 for parent_entry in parent_entries: | 504 for parent_entry in parent_entries: |
440 parent_entry.addEntry(mb_data, service=service, node=node) | 505 parent_entry.addEntry(mb_data, service=service, node=node) |