import demistomock as demisto # noqa: F401
from CommonServerPython import * # noqa: F401
import email.utils
from time import mktime
import feedparser
from feedparser.util import FeedParserDict
from markdownify import markdownify
def parse_feed_data(url):
"""Parses the data from the RSS feed.
Args:
feed_response (str): The raw data from the RSS feed.
Returns:
FeedParserDict: Parsed RSS feed data.
"""
try:
return feedparser.parse(url)
except Exception as err:
raise DemistoException(f"Failed to parse feed.\nError:\n{str(err)}", exception=err)
def collect_entries_data_from_response(parsed_feed_data: FeedParserDict, limit: Union[int, None]) -> List[Dict[str, Any]]:
"""Collects relevant data from the parsed RSS feed entries.
Args:
parsed_feed_data (FeedParserDict): Parsed RSS feed data.
limit (Union[int, None]): Maximum number of results to return.
Returns:
List[Dict[str, Any]]: The data from the RSS feed relevant for the widget.
"""
entries_data: List[Dict[str, Any]] = []
if not parsed_feed_data:
raise DemistoException("Could not parse feed data.")
if not limit:
return entries_data
for entry in parsed_feed_data.entries:
if entry:
published = email.utils.parsedate(entry.published)
if not published:
continue
published_dt = datetime.fromtimestamp(mktime(published))
published_formatted = published_dt.strftime("%B %-d, %Y %-I:%M %p")
entries_data.append(
{
"timestamp": published_formatted,
"link": entry.get("link"),
"title": entry.get("title"),
"summary": markdownify(entry.get("summary")),
"author": entry.get("author"),
}
)
if limit != "all":
limit -= 1
if limit == 0:
break
return entries_data
def create_widget_content(entries_data: List[Dict[str, Any]]) -> str:
"""Creates the human readable text for the widget.
Args:
entries_data (List[Dict[str, Any]]): The data from the RSS feed relevant for the widget.
Returns:
str: The widget's content.
"""
content: str = ""
for entry_data in entries_data:
content += f'**[{entry_data["title"]}]({entry_data["link"]})**\n'
# Markdown formatting is supported from 6.5
if is_demisto_version_ge("6.5"):
content += "{{color:#89A5C1}}" + f'(*Posted {entry_data["timestamp"]} by {entry_data["author"]}*)\n'
else:
content += f'*Posted {entry_data["timestamp"]} by {entry_data["author"]}*\n'
content += f'{entry_data["summary"]}\n'
content += "\n\n"
if not content:
content = "## No entries were found."
return content
def main():
args = demisto.args()
limit = sys.maxsize if not args.get("limit") else arg_to_number(args.get("limit"))
url = (
"https://live.paloaltonetworks.com/twzvq79624/rss/search?filter=includeBlogs%2Clabels&"
"collapse_discussion=true&search_type=thread&include_blogs=true&labels=cortex+xsoar"
)
try:
parsed_feed_data = parse_feed_data(url)
entries_data = collect_entries_data_from_response(parsed_feed_data, limit)
content = create_widget_content(entries_data)
except Exception as e:
return_error(str(e))
return_results(
{
"Type": EntryType.NOTE,
"ContentsFormat": EntryFormat.MARKDOWN,
"Contents": content,
}
)
if __name__ in ("__builtin__", "builtins", "__main__"): # pragma: no cover
main()