- Added Gravatar Integration

- Realtime Notify & Notify API
- Some bugs fixed
This commit is contained in:
2025-11-22 23:49:00 +01:00
parent 858c98412f
commit 2ef98ce897
17 changed files with 465 additions and 310 deletions

View File

@@ -51,13 +51,26 @@
<tbody>
{% for user in users %}
<tr>
<td>{% if user.profile_pic and user.profile_pic != 'default.png' %}<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" width="32" class="rounded me-1">{% endif %} {{ user.username }}</td>
<td>
{% if user.profile_pic and user.profile_pic != 'default.png' %}
{% if user.profile_pic.startswith('http') %}
<img src="{{ user.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
{{ user.username }}
</td>
<td>{{ user.email }}</td>
<td>{% if user.is_admin %}<i class="bi bi-check-lg text-success"></i>{% endif %}</td>
<td>{% if user.is_owner %}<i class="bi bi-star-fill text-warning"></i>{% endif %}</td>
<td>
{% if user.profile_pic and user.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" width="32" class="rounded me-1">
{% if user.profile_pic.startswith('http') %}
<img src="{{ user.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
<form action="{{ url_for('admin.admin_delete_pic', user_id=user.id) }}" method="post" style="display:inline;">
<button class="btn btn-danger btn-sm" title="{{ _('Delete Picture') }}"><i class="bi bi-image"></i></button>
</form>
@@ -103,9 +116,11 @@
<tr>
<td>
{% if post.user.profile_pic and post.user.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" alt="{{ post.user.username }}" class="rounded me-1" width="32">{{ post.user.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ post.user.username }}
{% if post.user.profile_pic.startswith('http') %}
<img src="{{ post.user.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
</td>
<td>{{ post.content|truncate(50) }}</td>
@@ -144,16 +159,20 @@
<tr>
<td>
{% if f.requester.profile_pic and f.requester.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ f.requester.profile_pic) }}" alt="{{ f.requester.username }}" class="rounded me-1" width="32">{{ f.requester.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ f.requester.username }}
{% if f.requester.profile_pic.startswith('http') %}
<img src="{{ f.requester.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ f.requester.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
</td>
<td>
{% if f.receiver.profile_pic and f.receiver.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ f.receiver.profile_pic) }}" alt="{{ f.receiver.username }}" class="rounded me-1" width="32">{{ f.receiver.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ f.receiver.username }}
{% if f.receiver.profile_pic.startswith('http') %}
<img src="{{ f.receiver.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ f.receiver.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
</td>
<td>
@@ -189,9 +208,11 @@
<tr>
<td>
{% if comment.user.profile_pic and comment.user.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ comment.user.profile_pic) }}" class="rounded me-2" width="32">{{ comment.user.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ comment.user.username }}
{% if comment.user.profile_pic.startswith('http') %}
<img src="{{ comment.user.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ comment.user.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
</td>
<td>{{ comment.post.id }}</td>
@@ -307,9 +328,11 @@
<tr>
<td>
{% if usi.user.profile_pic and usi.user.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ usi.user.profile_pic) }}" class="rounded me-2" width="32">{{ usi.user.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ usi.user.username }}
{% if usi.user.profile_pic.startswith('http') %}
<img src="{{ usi.user.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ usi.user.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
</td>
<td>{{ usi.item.name }}</td>
@@ -335,9 +358,11 @@
<tr>
<td>
{% if user.profile_pic and user.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" class="rounded me-2" width="32">{{ user.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ user.username }}
{% if user.profile_pic.startswith('http') %}
<img src="{{ user.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
</td>
<td>{{ user.reward_points() }}</td>
@@ -358,7 +383,7 @@
</table>
</div>
</div>
<script src="{{ url_for('static', filename='js/adstop.js') }}"></script>
<script src="{{ url_for('static', filename='js/adtab.js') }}"></script>
<script>
var triggerTabList = [].slice.call(document.querySelectorAll('#adminTab button'))
triggerTabList.forEach(function (triggerEl) {

View File

@@ -8,6 +8,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<script src="{{ url_for('static', filename='js/translate.js') }}"></script>
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
@@ -43,7 +44,7 @@
<li class="nav-item"><a class="nav-link" href="{{ url_for('user.users') }}"><i class="bi bi-people me-1"></i>{{ _('Users') }}</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('friend.friends') }}"><i class="bi bi-person-check me-1"></i>{{ _('Friends') }}</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('profil.my_posts') }}"><i class="bi bi-file-earmark-text me-1"></i>{{ _('My Posts') }}</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('notif.notifications') }}"><i class="bi bi-bell me-1"></i>{{ _('Notifications') }}</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('notif.notifications') }}"><span class="badge bg-secondary" id="message_count">0</span><i class="bi bi-bell me-1"></i>{{ _('Notifications') }}</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('profil.profile') }}"><i class="bi bi-person-circle me-1"></i>{{ _('Profile') }}</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('log.logout') }}"><i class="bi bi-box-arrow-right me-1"></i>{{ _('Logout') }}</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('support.support') }}"><i class="bi bi-question-circle me-1"></i>{{ _('Support') }}</a></li>
@@ -80,10 +81,18 @@
{% endwith %}
<div class="d-flex align-items-center mb-3">
{% if user.profile_pic and user.profile_pic != 'default.png' %}
{% if SHOPITEM_ID_GOLDRAHMEN in user.shop_items | map(attribute='item_id') | list %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" class="profile-pic me-2" style="border-color: gold;">
{% if user.profile_pic.startswith('http') %}
{% if SHOPITEM_ID_GOLDRAHMEN in user.shop_items | map(attribute='item_id') | list %}
<img src="{{ user.profile_pic }}" class="profile-pic me-2" style="border-color: gold;" alt="Profile Picture">
{% else %}
<img src="{{ user.profile_pic }}" class="profile-pic me-2" alt="Profile Picture">
{% endif %}
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" class="profile-pic me-2">
{% if SHOPITEM_ID_GOLDRAHMEN in user.shop_items | map(attribute='item_id') | list %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" class="profile-pic me-2" style="border-color: gold;">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user.profile_pic) }}" class="profile-pic me-2">
{% endif %}
{% endif %}
{% endif %}
{% if user.is_authenticated %}
@@ -108,6 +117,24 @@
&middot; <a href="{{ url_for('credit.credits') }}" class="text-decoration-none">{{ _('Credits') }}</a>
</span>
</div>
</footer>
</footer>
<script>
function set_message_count(n) {
$('#message_count').text(n);
}
{% if current_user.is_authenticated %}
$(function() {
setInterval(function() {
$.ajax("{{ url_for('notif.notifications_api') }}").done(
function(notifications) {
for (var i = 0; i < notifications.length; i++) {
set_message_count(i + 1);
}
}
);
}, 1000);
});
{% endif %}
</script>
</body>
</html>

View File

@@ -30,13 +30,21 @@
<div class="card-body">
<div class="d-flex align-items-center mb-2">
{% if post.user.profile_pic and post.user.profile_pic != 'default.png' %}
{% if SHOPITEM_ID_GOLDRAHMEN in post.user.shop_items | map(attribute='item_id') | list %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" class="profile-pic me-2" style="border-color: gold;">
{% if post.user.profile_pic.startswith('http') %}
{% if SHOPITEM_ID_GOLDRAHMEN in post.user.shop_items | map(attribute='item_id') | list %}
<img src="{{ post.user.profile_pic }}" class="profile-pic me-2" style="border-color: gold;" alt="Profile Picture">
{% else %}
<img src="{{ post.user.profile_pic }}" class="profile-pic me-2" alt="Profile Picture">
{% endif %}
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" class="profile-pic me-2">
{% if SHOPITEM_ID_GOLDRAHMEN in post.user.shop_items | map(attribute='item_id') | list %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" class="profile-pic me-2" style="border-color: gold;">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" class="profile-pic me-2">
{% endif %}
{% endif %}
{% else %}
<i class="bi bi-person-circle me-2"></i>
<i class="bi bi-person-circle me-2"></i>
{% endif %}
<strong>{{ post.user.username }}</strong>
</div>
@@ -118,5 +126,4 @@
{{ _('No posts available.') }}
</div>
{% endif %}
<script src="{{ url_for('static', filename='js/feed.js') }}"></script>
{% endblock %}

View File

@@ -7,10 +7,23 @@
<li class="list-group-item d-flex justify-content-between align-items-center">
<span>
{% if friend.profile_pic and friend.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' + friend.profile_pic) }}" alt="{{ friend.username }}" class="profile-pic me-2">{{ friend.username }}
{% if friend.profile_pic.startswith('http') %}
{% if SHOPITEM_ID_GOLDRAHMEN in friend.shop_items | map(attribute='item_id') | list %}
<img src="{{ friend.profile_pic }}" class="profile-pic me-2" style="border-color: gold;" alt="Profile Picture">
{% else %}
<img src="{{ friend.profile_pic }}" class="profile-pic me-2" alt="Profile Picture">
{% endif %}
{% else %}
{% if SHOPITEM_ID_GOLDRAHMEN in friend.shop_items | map(attribute='item_id') | list %}
<img src="{{ url_for('static', filename='profile_pics/' ~ friend.profile_pic) }}" class="profile-pic me-2" style="border-color: gold;">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ friend.profile_pic) }}" class="profile-pic me-2">
{% endif %}
{% endif %}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ friend.username }}
<i class="bi bi-person-circle me-2"></i>
{% endif %}
{{ friend.username }}
</span>
<form action="{{ url_for('friend.remove_friend', user_id=friend.id) }}" method="post" style="display:inline;">
<button class="btn btn-warning btn-sm"><i class="bi bi-person-dash"></i> {{ _('Remove Friend') }}</button>
@@ -26,10 +39,23 @@
<li class="list-group-item d-flex justify-content-between align-items-center">
<span>
{% if req.requester.profile_pic and req.requester.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' + req.requester.profile_pic) }}" alt="{{ req.requester.username }}" class="profile-pic me-2">{{ req.requester.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ req.requester.username }}
{% endif %}
{% if req.requester.profile_pic.startswith('http') %}
{% if SHOPITEM_ID_GOLDRAHMEN in req.requester.shop_items | map(attribute='item_id') | list %}
<img src="{{ req.requester.profile_pic }}" class="profile-pic me-2" style="border-color: gold;" alt="Profile Picture">
{% else %}
<img src="{{ req.requester.profile_pic }}" class="profile-pic me-2" alt="Profile Picture">
{% endif %}
{% else %}
{% if SHOPITEM_ID_GOLDRAHMEN in req.requester.shop_items | map(attribute='item_id') | list %}
<img src="{{ url_for('static', filename='profile_pics/' ~ req.requester.profile_pic) }}" class="profile-pic me-2" style="border-color: gold;">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ req.requester.profile_pic) }}" class="profile-pic me-2">
{% endif %}
{% endif %}
{% else %}
<i class="bi bi-person-circle me-2"></i>
{% endif %}
{{ req.requester.username }}
</span>
<div>
<form action="{{ url_for('friend.accept_friend', friendship_id=req.id) }}" method="post" style="display:inline;">

View File

@@ -7,13 +7,21 @@
<div class="card-body">
<div class="d-flex align-items-center mb-2">
{% if post.user.profile_pic and post.user.profile_pic != 'default.png' %}
{% if SHOPITEM_ID_GOLDRAHMEN in post.user.shop_items | map(attribute='item_id') | list %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" class="profile-pic me-2" style="border-color: gold;">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" class="profile-pic me-2">
{% endif %}
{% if post.user.profile_pic.startswith('http') %}
{% if SHOPITEM_ID_GOLDRAHMEN in post.user.shop_items | map(attribute='item_id') | list %}
<img src="{{ post.user.profile_pic }}" class="profile-pic me-2" style="border-color: gold;" alt="Profile Picture">
{% else %}
<img src="{{ post.user.profile_pic }}" class="profile-pic me-2" alt="Profile Picture">
{% endif %}
{% else %}
<i class="bi bi-person-circle me-1"></i>
{% if SHOPITEM_ID_GOLDRAHMEN in post.user.shop_items | map(attribute='item_id') | list %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" class="profile-pic me-2" style="border-color: gold;">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ post.user.profile_pic) }}" class="profile-pic me-2">
{% endif %}
{% endif %}
{% else %}
<i class="bi bi-person-circle me-2"></i>
{% endif %}
<strong>{{ post.user.username }}</strong>
</div>

View File

@@ -3,10 +3,15 @@
{% block content %}
<p><i class="bi bi-envelope-at me-1"></i>{{ _('Email') }}: {{ user.email }}</p>
{% if not user.profile_pic.startswith('http') %}
<form action="{{ url_for('user.upload_pic') }}" method="post" enctype="multipart/form-data" class="mb-3">
<input type="file" name="profile_pic" required>
<button class="btn btn-secondary btn-sm" type="submit"><i class="bi bi-upload"></i> {{ _('Upload Picture') }}</button>
</form>
<form action="{{ url_for('user.gravatar') }}" method="post" style="display:inline;">
<button class="btn btn-secondary btn-sm"><i class="bi bi-globe"></i> {{ _('Use Gravatar') }}</button>
</form>
{% endif %}
{% if user.profile_pic and user.profile_pic != 'default.png' %}
<form action="{{ url_for('user.delete_pic') }}" method="post" style="display:inline;">
<button class="btn btn-danger btn-sm"><i class="bi bi-trash"></i> {{ _('Delete Picture') }}</button>

View File

@@ -18,9 +18,11 @@
<tr>
<td>
{% if req.user.profile_pic and req.user.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ req.user.profile_pic) }}" class="rounded me-2" width="32">{{ req.user.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ req.user.username }}
{% if req.user.profile_pic.startswith('http') %}
<img src="{{ req.user.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ req.user.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
</td>
<td>{{ req.requested_at.strftime('%Y-%m-%d %H:%M') }}</td>
@@ -48,9 +50,11 @@
<tr>
<td>
{% if req.user.profile_pic and req.user.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ req.user.profile_pic) }}" class="rounded me-2" width="32">{{ req.user.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ req.user.username }}
{% if req.user.profile_pic.startswith('http') %}
<img src="{{ req.user.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ req.user.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
</td>
<td>{{ req.requested_at.strftime('%Y-%m-%d %H:%M') }}</td>
@@ -73,9 +77,11 @@
<tr>
<td>
{% if req.user.profile_pic and req.user.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' ~ req.user.profile_pic) }}" class="rounded me-2" width="32">{{ req.user.username }}
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ req.user.username }}
{% if req.user.profile_pic.startswith('http') %}
<img src="{{ req.user.profile_pic }}" width="32" class="rounded me-1" alt="Profile Picture">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ req.user.profile_pic) }}" width="32" class="rounded me-1" alt="Profile Picture">
{% endif %}
{% endif %}
</td>
<td>{{ req.requested_at.strftime('%Y-%m-%d %H:%M') }}</td>

View File

@@ -6,11 +6,24 @@
{% for user_item in users %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<span>
{% if user_item.profile_pic and user_item.profile_pic != 'default.png' %}
<img src="{{ url_for('static', filename='profile_pics/' + user_item.profile_pic) }}" alt="{{ user_item.username }}" class="profile-pic me-2">{{ user_item.username }}
{% if user_item.profile_pic and user_item.profile_pic != 'default.png' %}
{% if user_item.profile_pic.startswith('http') %}
{% if SHOPITEM_ID_GOLDRAHMEN in user_item.shop_items | map(attribute='item_id') | list %}
<img src="{{ user_item.profile_pic }}" class="profile-pic me-2" style="border-color: gold;" alt="Profile Picture">
{% else %}
<i class="bi bi-person-circle me-1"></i>{{ user_item.username }}
<img src="{{ user_item.profile_pic }}" class="profile-pic me-2" alt="Profile Picture">
{% endif %}
{% else %}
{% if SHOPITEM_ID_GOLDRAHMEN in user_item.shop_items | map(attribute='item_id') | list %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user_item.profile_pic) }}" class="profile-pic me-2" style="border-color: gold;">
{% else %}
<img src="{{ url_for('static', filename='profile_pics/' ~ user_item.profile_pic) }}" class="profile-pic me-2">
{% endif %}
{% endif %}
{% else %}
<i class="bi bi-person-circle me-2"></i>
{% endif %}
{{ user_item.username }}
</span>
<div>
{% if user_item.id != user.id %}