def tag(self, new_tags, strict=False, expiration=None): """Tags an observable. An observable can be tagged to add more information as to what it represents. Args: new_tags: An array of strings to tag the observable with. strict: Set to ``True`` to replace all existing tags with the ``new_tags``. expiration: Timedelta field after which the Tag will not be considered fresh anymore. Returns: A fresh Observable instance as reloaded from the database. """ new_tags = iterify(new_tags) if strict: remove = set([t.name for t in self.tags]) - set(new_tags) for tag in remove: self.modify(pull__tags__name=tag) tagged = False for new_tag in new_tags: if new_tag.strip() != '': tagged = True new_tag = Tag(name=new_tag) new_tag.clean() try: # check if tag is a replacement tag = Tag.objects.get(replaces=new_tag.name) except DoesNotExist: tag = Tag.get_or_create(name=new_tag.name) if not expiration: expiration = tag.default_expiration extra_tags = tag.produces + [tag] # search for related entities and link them for e in Entity.objects(tags__in=[tag.name]): self.active_link_to(e, 'Tagged', 'tags', clean_old=False) for tag in extra_tags: if not self.modify( {"tags__name": tag.name}, set__tags__S__fresh=True, set__tags__S__last_seen=datetime.utcnow()): self.modify(push__tags=ObservableTag( name=tag.name, expiration=expiration)) tag.modify(inc__count=1) if tagged: self.update(set__last_tagged=datetime.utcnow()) return self.reload()