Skip to content

Commit 94fd9f8

Browse files
jaegeraljkppr
andauthored
Fix: Removal Logic Bug in Annotation Mixins (#3323)
* Fixing a bug in the set_status function that allowed for multiple entries in that list. * Also fixed similar issues with the `remove_label` and `remove_comment` functions. * Added a warning for now to surface instances where the problem still occurs. --------- Co-authored-by: Janosch <99879757+jkppr@users.noreply.github.com>
1 parent 9432439 commit 94fd9f8

File tree

2 files changed

+72
-14
lines changed

2 files changed

+72
-14
lines changed

timesketch/models/annotations.py

+54-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from __future__ import unicode_literals
1919

2020
import json
21+
import logging
2122
import six
2223

2324
from sqlalchemy import Column
@@ -32,6 +33,8 @@
3233
from timesketch.models import BaseModel
3334
from timesketch.models import db_session
3435

36+
logger = logging.getLogger("timesketch.models.annotations")
37+
3538

3639
class BaseAnnotation(object):
3740
"""Base class with common attributes."""
@@ -140,9 +143,20 @@ def remove_label(self, label):
140143
Args:
141144
label: Name of the label.
142145
"""
143-
for label_obj in self.labels:
144-
if label_obj.label.lower() != label.lower():
145-
continue
146+
labels_to_remove = [
147+
label_obj
148+
for label_obj in self.labels
149+
if label_obj.label.lower() == label.lower()
150+
]
151+
152+
if not labels_to_remove:
153+
logger.warning(
154+
"Attempted to remove non-existent label: %s from object: %s",
155+
str(label),
156+
str(type(self).__name__),
157+
)
158+
159+
for label_obj in labels_to_remove:
146160
self.labels.remove(label_obj)
147161
db_session.add(self)
148162
db_session.commit()
@@ -244,15 +258,25 @@ def remove_comment(self, comment_id):
244258
245259
Args:
246260
comment_id: Id of the comment.
261+
262+
Returns:
263+
True if the comment was removed, False otherwise.
247264
"""
248-
for comment_obj in self.comments:
249-
if comment_obj.id == int(comment_id):
250-
self.comments.remove(comment_obj)
251-
db_session.add(self)
252-
db_session.commit()
253-
return True
254265

255-
return False
266+
comments_to_remove = [
267+
comment_obj
268+
for comment_obj in self.comments
269+
if comment_obj.id == int(comment_id)
270+
]
271+
if not comments_to_remove:
272+
logger.debug("Comment to delete not found")
273+
return False # Comment not found
274+
for comment_obj in comments_to_remove:
275+
logger.debug("Removing comment")
276+
self.comments.remove(comment_obj)
277+
db_session.add(self)
278+
db_session.commit()
279+
return True
256280

257281
def get_comment(self, comment_id):
258282
"""Retrieves a comment.
@@ -329,8 +353,7 @@ def set_status(self, status):
329353
Args:
330354
status: Name of the status
331355
"""
332-
for _status in self.status:
333-
self.status.remove(_status)
356+
self.status = [] # replace the list with an empty list.
334357
self.status.append(self.Status(user=None, status=status))
335358
db_session.add(self)
336359
db_session.commit()
@@ -339,11 +362,30 @@ def set_status(self, status):
339362
def get_status(self):
340363
"""Get the current status.
341364
365+
Only one status should be in the database at a time.
366+
367+
Raises:
368+
RuntimeError: If more than one status is available.
369+
342370
Returns:
343371
The status as a string
344372
"""
345373
if not self.status:
346374
self.status.append(self.Status(user=None, status="new"))
375+
if len(self.status) > 1:
376+
self_id = self.id if hasattr(self, "id") else None
377+
# TODO: Change from warning to raising an exception once we ensured
378+
# it won't affect the deployment.
379+
# raise RuntimeError(
380+
# "More than one status available for object [%s] with ID: [%s]",
381+
# str(type(self).__name__),
382+
# str(self_id),
383+
# )
384+
logging.warning(
385+
"More than one status available for object [%s] with ID: [%s]",
386+
str(type(self).__name__),
387+
str(self_id),
388+
)
347389
return self.status[0]
348390

349391

timesketch/tsctl.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -612,9 +612,9 @@ def sketch_info(sketch_id):
612612
"user_id",
613613
],
614614
]
615-
for status in sketch.status:
615+
for _status in sketch.status:
616616
status_table.append(
617-
[status.id, status.status, status.created_at, status.user_id]
617+
[_status.id, _status.status, _status.created_at, _status.user_id]
618618
)
619619
print("Status:")
620620
print_table(status_table)
@@ -671,6 +671,22 @@ def timeline_status(timeline_id, action, status):
671671
]
672672
)
673673
print_table(table_data)
674+
675+
status_table = [
676+
[
677+
"id",
678+
"status",
679+
"created_at",
680+
"user_id",
681+
],
682+
]
683+
for _status in timeline.status:
684+
status_table.append(
685+
[_status.id, _status.status, _status.created_at, _status.user_id]
686+
)
687+
print("Status:")
688+
print_table(status_table)
689+
674690
elif action == "set":
675691
timeline = Timeline.query.filter_by(id=timeline_id).first()
676692
if not timeline:

0 commit comments

Comments
 (0)