import re
from datetime import datetime
from flask import url_for
from slugify import slugify
def format_datetime(dt):
"""Format datetime for display"""
if not dt:
return ""
now = datetime.utcnow()
diff = now - dt
if diff.days == 0:
# Today
if diff.seconds < 60:
return "Just now"
if diff.seconds < 3600:
minutes = diff.seconds // 60
return f"{minutes} minute{'s' if minutes != 1 else ''} ago"
else:
hours = diff.seconds // 3600
return f"{hours} hour{'s' if hours != 1 else ''} ago"
elif diff.days == 1:
return "Yesterday"
elif diff.days < 7:
return f"{diff.days} days ago"
else:
return dt.strftime("%b %d, %Y")
def get_username_for_mention(text):
"""Extract username from a @mention"""
pattern = r'@([a-zA-Z0-9_]+)'
matches = re.findall(pattern, text)
return matches
def make_url_slug(text):
"""Create a URL-friendly slug from text"""
return slugify(text)
def truncate_text(text, length=100):
"""Truncate text to specified length and add ellipsis if needed"""
if len(text) <= length:
return text
return text[:length].rsplit(' ', 1)[0] + '...'
def get_avatar_url(avatar_filename):
"""Get the URL for user avatar"""
if not avatar_filename or avatar_filename == 'default.png':
return url_for('static', filename='uploads/avatars/default.png')
return url_for('static', filename=f'uploads/avatars/{avatar_filename}')
def parse_bbcode(text):
"""Convert basic BBCode to HTML (simple implementation)"""
# Bold
text = re.sub(r'\[b\](.*?)\[/b\]', r'\1', text)
# Italic
text = re.sub(r'\[i\](.*?)\[/i\]', r'\1', text)
# Underline
text = re.sub(r'\[u\](.*?)\[/u\]', r'\1', text)
# URLs
text = re.sub(r'\[url=(.*?)\](.*?)\[/url\]', r'\2', text)
text = re.sub(r'\[url\](.*?)\[/url\]', r'\1', text)
# Images
text = re.sub(r'\[img\](.*?)\[/img\]', r'', text)
# Code blocks
text = re.sub(r'\[code\](.*?)\[/code\]', r'
\1
', text, flags=re.DOTALL)
# Quotes
text = re.sub(r'\[quote\](.*?)\[/quote\]', r'\1', text, flags=re.DOTALL) text = re.sub(r'\[quote=(.*?)\](.*?)\[/quote\]', r'
\2', text, flags=re.DOTALL) return text