This commit is contained in:
@ -83,43 +83,110 @@ class BaseLogData(JSONDataclass):
|
||||
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def _format_timestamp(ts: str) -> str:
|
||||
from datetime import datetime, timezone
|
||||
import re
|
||||
|
||||
cleaned = ts.strip().strip("[]")
|
||||
dt = None
|
||||
|
||||
if cleaned.isdigit():
|
||||
try:
|
||||
seconds = int(cleaned)
|
||||
dt = datetime.fromtimestamp(seconds, tz=timezone.utc)
|
||||
except (ValueError, OSError):
|
||||
pass
|
||||
|
||||
if dt is None:
|
||||
for fmt in [
|
||||
"%Y-%m-%dT%H:%M:%S.%fZ",
|
||||
"%Y-%m-%dT%H:%M:%SZ",
|
||||
"%Y-%m-%dT%H:%M:%S.%f",
|
||||
"%Y-%m-%dT%H:%M:%S",
|
||||
]:
|
||||
try:
|
||||
dt = datetime.strptime(cleaned, fmt)
|
||||
break
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
if dt is None:
|
||||
m = re.match(
|
||||
r"(\d{4}-\d{2}-\d{2})\s+\w{3}\s+(\d{2}:\d{2})", cleaned
|
||||
)
|
||||
if m:
|
||||
try:
|
||||
dt = datetime.strptime(
|
||||
f"{m.group(1)} {m.group(2)}", "%Y-%m-%d %H:%M"
|
||||
)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if dt is None:
|
||||
try:
|
||||
dt = datetime.fromisoformat(cleaned)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if dt:
|
||||
return dt.strftime("%b %-d, %Y %-I:%M %p")
|
||||
return ts
|
||||
|
||||
def notes_as_html(self) -> str:
|
||||
import html
|
||||
import bleach
|
||||
import markdown
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
if not self.notes:
|
||||
return ""
|
||||
|
||||
html_notes = []
|
||||
md = markdown.Markdown(extensions=["extra"])
|
||||
allowed_tags = [
|
||||
"p", "br", "strong", "em", "a", "ul", "ol", "li",
|
||||
"code", "pre", "blockquote", "h1", "h2", "h3", "h4", "h5", "h6",
|
||||
"hr", "img",
|
||||
]
|
||||
|
||||
note_items = []
|
||||
|
||||
if isinstance(self.notes, dict):
|
||||
for ts, text in self.notes.items():
|
||||
note_text = " ".join(text.strip().split())
|
||||
html_notes.append(
|
||||
f'<div class="sticky-note">{ts}: {note_text}</div>'
|
||||
)
|
||||
for ts, text in sorted(self.notes.items(), reverse=True):
|
||||
note_items.append((ts, text.strip()))
|
||||
elif isinstance(self.notes, str):
|
||||
for line in self.notes.split("\n"):
|
||||
if line.strip():
|
||||
escaped_line = html.escape(line)
|
||||
html_notes.append(f'<div class="sticky-note">{escaped_line}</div>')
|
||||
note_items.append((None, line.strip()))
|
||||
elif isinstance(self.notes, list):
|
||||
for note in self.notes:
|
||||
if isinstance(note, dict):
|
||||
timestamp, note_text = next(iter(note.items()))
|
||||
note_text = " ".join(note_text.strip().split())
|
||||
html_notes.append(
|
||||
f'<div class="sticky-note">{timestamp}: {note_text}</div>'
|
||||
)
|
||||
note_items.append((timestamp, note_text.strip()))
|
||||
elif isinstance(note, str):
|
||||
for line in note.split("\n"):
|
||||
if line.strip():
|
||||
escaped_line = html.escape(line)
|
||||
html_notes.append(
|
||||
f'<div class="sticky-note">{escaped_line}</div>'
|
||||
)
|
||||
note_items.append((None, line.strip()))
|
||||
|
||||
return mark_safe("".join(html_notes))
|
||||
html_parts = []
|
||||
for i, (ts, text) in enumerate(note_items):
|
||||
if i > 0:
|
||||
html_parts.append('<hr class="note-divider">')
|
||||
|
||||
ts_html = ""
|
||||
if ts:
|
||||
ts_html = f'<h5 class="note-timestamp">{self._format_timestamp(ts)}</h5>'
|
||||
|
||||
content_html = bleach.clean(
|
||||
md.convert(text),
|
||||
tags=allowed_tags,
|
||||
strip=True,
|
||||
)
|
||||
|
||||
html_parts.append(
|
||||
f'<div class="note-item">{ts_html}<div class="note-content">{content_html}</div></div>'
|
||||
)
|
||||
|
||||
return mark_safe("".join(html_parts))
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
Reference in New Issue
Block a user