| 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: |
| |
| 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)""" |
| |
| text = re.sub(r'\[b\](.*?)\[/b\]', r'<strong>\1</strong>', text) |
| |
| text = re.sub(r'\[i\](.*?)\[/i\]', r'<em>\1</em>', text) |
| |
| text = re.sub(r'\[u\](.*?)\[/u\]', r'<u>\1</u>', text) |
| |
| text = re.sub(r'\[url=(.*?)\](.*?)\[/url\]', r'<a href="\1" target="_blank">\2</a>', text) |
| text = re.sub(r'\[url\](.*?)\[/url\]', r'<a href="\1" target="_blank">\1</a>', text) |
| |
| text = re.sub(r'\[img\](.*?)\[/img\]', r'<img src="\1" alt="User posted image" class="img-fluid">', text) |
| |
| text = re.sub(r'\[code\](.*?)\[/code\]', r'<pre><code>\1</code></pre>', text, flags=re.DOTALL) |
| |
| text = re.sub(r'\[quote\](.*?)\[/quote\]', r'<blockquote>\1</blockquote>', text, flags=re.DOTALL) |
| text = re.sub(r'\[quote=(.*?)\](.*?)\[/quote\]', r'<blockquote>\2<footer>\1</footer></blockquote>', text, flags=re.DOTALL) |
| |
| return text |
|
|