Auto commit: 2026-02-09T19:20:56.861Z

This commit is contained in:
Flatlogic Bot 2026-02-09 19:20:57 +00:00
parent 42369b6e1a
commit 97ab8247f6
12 changed files with 165 additions and 5 deletions

View File

@ -164,3 +164,46 @@ you should set broker_connection_retry_on_startup to True.
[2026-02-09 18:31:03,713: INFO/ForkPoolWorker-1] Decoded JSON for 27: summary=True, tags=['development', 'research', 'new', 'company'] [2026-02-09 18:31:03,713: INFO/ForkPoolWorker-1] Decoded JSON for 27: summary=True, tags=['development', 'research', 'new', 'company']
[2026-02-09 18:31:03,987: INFO/ForkPoolWorker-1] Successfully added tags ['development', 'research', 'new', 'company'] to bookmark 27 [2026-02-09 18:31:03,987: INFO/ForkPoolWorker-1] Successfully added tags ['development', 'research', 'new', 'company'] to bookmark 27
[2026-02-09 18:31:04,321: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[944ef664-f321-45b6-82f8-607291008ea6] succeeded in 13.666462198016234s: 'Generated summary and tags for bookmark 27' [2026-02-09 18:31:04,321: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[944ef664-f321-45b6-82f8-607291008ea6] succeeded in 13.666462198016234s: 'Generated summary and tags for bookmark 27'
[2026-02-09 19:04:23,495: INFO/MainProcess] Task core.tasks.process_bookmark[70bb649c-6afd-477d-ac5f-959b9ea12bb0] received
[2026-02-09 19:04:26,064: INFO/ForkPoolWorker-2] HTTP Request: GET https://facebook.com "HTTP/1.1 301 Moved Permanently"
[2026-02-09 19:04:26,361: INFO/ForkPoolWorker-2] HTTP Request: GET https://www.facebook.com/ "HTTP/1.1 400 Bad Request"
[2026-02-09 19:04:26,399: WARNING/ForkPoolWorker-2] Error fetching bookmark 28 (https://facebook.com): Client error '400 Bad Request' for url 'https://www.facebook.com/'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400. Trying base domain backup.
[2026-02-09 19:04:26,403: ERROR/ForkPoolWorker-2] Error fetching base domain for bookmark 28: Client error '400 Bad Request' for url 'https://www.facebook.com/'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400
[2026-02-09 19:04:27,088: INFO/MainProcess] Task core.tasks.generate_summary[b0feb8a7-8741-4581-a7f0-7e703e4a2e70] received
[2026-02-09 19:04:27,151: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[70bb649c-6afd-477d-ac5f-959b9ea12bb0] succeeded in 3.190528256993275s: 'Processed bookmark 28'
[2026-02-09 19:04:28,313: INFO/ForkPoolWorker-1] Generating summary/tags for bookmark 28...
[2026-02-09 19:04:39,614: INFO/ForkPoolWorker-1] AI Raw Response for 28: {
"summary": "The webpage content could not be retrieved; requests to https://facebook.com and its base domain failed. No content was available for analysis, so no page details can be provided."
}
[2026-02-09 19:04:39,614: INFO/ForkPoolWorker-1] Decoded JSON for 28: summary=True, tags=[]
[2026-02-09 19:04:40,920: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[b0feb8a7-8741-4581-a7f0-7e703e4a2e70] succeeded in 13.627130784036126s: 'Generated summary for bookmark 28'
[2026-02-09 19:08:50,036: INFO/MainProcess] Task core.tasks.process_bookmark[ff409078-4458-47ef-b732-facaaf2cd761] received
[2026-02-09 19:08:50,262: INFO/ForkPoolWorker-2] HTTP Request: GET https://youtube.com "HTTP/1.1 301 Moved Permanently"
[2026-02-09 19:08:50,403: INFO/ForkPoolWorker-2] HTTP Request: GET https://www.youtube.com/ "HTTP/1.1 200 OK"
[2026-02-09 19:08:50,858: INFO/MainProcess] Task core.tasks.generate_summary[57582068-b4a2-48dc-9357-6d22a1ba1778] received
[2026-02-09 19:08:50,865: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[ff409078-4458-47ef-b732-facaaf2cd761] succeeded in 0.824686923995614s: 'Processed bookmark 29'
[2026-02-09 19:08:50,927: INFO/ForkPoolWorker-1] Generating summary/tags for bookmark 29...
[2026-02-09 19:09:01,754: INFO/ForkPoolWorker-1] AI Raw Response for 29: {
"summary": "This is a YouTube footer listing navigational and legal links (About, Press, Copyright, Contact, Creators, Advertise, Developers, Terms, Privacy, Policy & Safety, How YouTube works, and Test new features). It also includes a 2026 copyright attribution to Google LLC."
}
[2026-02-09 19:09:01,754: INFO/ForkPoolWorker-1] Decoded JSON for 29: summary=True, tags=[]
[2026-02-09 19:09:01,769: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[57582068-b4a2-48dc-9357-6d22a1ba1778] succeeded in 10.908533619949594s: 'Generated summary for bookmark 29'
[2026-02-09 19:09:42,382: INFO/MainProcess] Task core.tasks.process_bookmark[21590aeb-6045-4341-8f97-80291d55e5bb] received
[2026-02-09 19:09:42,476: INFO/ForkPoolWorker-2] HTTP Request: GET https://youtube.com "HTTP/1.1 301 Moved Permanently"
[2026-02-09 19:09:42,577: INFO/ForkPoolWorker-2] HTTP Request: GET https://www.youtube.com/ "HTTP/1.1 200 OK"
[2026-02-09 19:09:42,874: INFO/MainProcess] Task core.tasks.generate_summary[3a3f1ae2-e049-44a0-8743-e0dd2392820f] received
[2026-02-09 19:09:42,877: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[21590aeb-6045-4341-8f97-80291d55e5bb] succeeded in 0.48919728299370036s: 'Processed bookmark 29'
[2026-02-09 19:09:43,056: INFO/ForkPoolWorker-2] Generating summary/tags for bookmark 29...
[2026-02-09 19:09:53,936: INFO/ForkPoolWorker-2] AI Raw Response for 29: {
"summary": "The content is a YouTube footer listing navigation links to corporate and support resources — About, Press, Copyright, Contact, Creators, Advertise, Developers, Terms, Privacy, Policy & Safety, How YouTube works, and Test new features. It also includes a copyright notice attributing the site to Google LLC (2026)."
}
[2026-02-09 19:09:53,938: INFO/ForkPoolWorker-2] Decoded JSON for 29: summary=True, tags=[]
[2026-02-09 19:09:53,962: INFO/ForkPoolWorker-2] Task core.tasks.generate_summary[3a3f1ae2-e049-44a0-8743-e0dd2392820f] succeeded in 11.077497629041318s: 'Generated summary for bookmark 29'
[2026-02-09 19:20:12,359: INFO/MainProcess] Task core.tasks.process_bookmark[e19646b8-ea58-48a7-89e1-3d0429b9030a] received
[2026-02-09 19:20:26,876: INFO/ForkPoolWorker-2] HTTP Request: GET https://instagram.com "HTTP/1.1 301 Moved Permanently"
[2026-02-09 19:20:28,386: INFO/ForkPoolWorker-2] HTTP Request: GET https://www.instagram.com/ "HTTP/1.1 200 OK"
[2026-02-09 19:20:39,598: INFO/MainProcess] Task core.tasks.generate_summary[cfcfea70-d5a2-4694-9467-45333ac44d3f] received
[2026-02-09 19:20:40,610: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[e19646b8-ea58-48a7-89e1-3d0429b9030a] succeeded in 24.209723198961s: 'Processed bookmark 30'
[2026-02-09 19:20:51,094: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[cfcfea70-d5a2-4694-9467-45333ac44d3f] succeeded in 8.763452520011924s: None

View File

@ -58,6 +58,7 @@ INSTALLED_APPS = [
'rest_framework', 'rest_framework',
'taggit', 'taggit',
'django_filters', 'django_filters',
'auditlog',
'core', 'core',
] ]
@ -67,6 +68,7 @@ MIDDLEWARE = [
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'auditlog.middleware.AuditlogMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
# Disable X-Frame-Options middleware to allow Flatlogic preview iframes. # Disable X-Frame-Options middleware to allow Flatlogic preview iframes.
# 'django.middleware.clickjacking.XFrameOptionsMiddleware', # 'django.middleware.clickjacking.XFrameOptionsMiddleware',

View File

@ -83,3 +83,9 @@ class APIToken(models.Model):
def __str__(self): def __str__(self):
return f"{self.name} - {self.user.username}" return f"{self.name} - {self.user.username}"
from auditlog.registry import auditlog
auditlog.register(Bookmark)
auditlog.register(Team)
auditlog.register(TeamMembership)
auditlog.register(APIToken)

View File

@ -140,6 +140,7 @@
<li><a class="dropdown-item" href="/admin/">Admin Panel</a></li> <li><a class="dropdown-item" href="/admin/">Admin Panel</a></li>
<li><a class="dropdown-item" href="/flower/">Task Monitor</a></li> <li><a class="dropdown-item" href="/flower/">Task Monitor</a></li>
{% endif %} {% endif %}
<li><a class="dropdown-item" href="{% url 'activity-log' %}">Activity Log</a></li>
<li><hr class="dropdown-divider"></li> <li><hr class="dropdown-divider"></li>
<li> <li>
<form method="post" action="{% url 'logout' %}"> <form method="post" action="{% url 'logout' %}">

View File

@ -0,0 +1,94 @@
{% extends "base.html" %}
{% block title %}Activity Log{% endblock %}
{% block content %}
<div class="row mb-4">
<div class="col-12">
<h1 class="display-6 fw-bold text-primary">Activity Log</h1>
<p class="text-muted">History of your actions and changes.</p>
</div>
</div>
<div class="card shadow-sm border-0">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-4">Time</th>
<th>Action</th>
<th>Resource</th>
<th>Details</th>
</tr>
</thead>
<tbody>
{% for entry in log_entries %}
<tr>
<td class="ps-4 text-nowrap text-muted small">
{{ entry.timestamp|date:"M d, Y H:i" }}
</td>
<td>
{% if entry.action == 0 %}
<span class="badge bg-success bg-opacity-10 text-success rounded-pill">Created</span>
{% elif entry.action == 1 %}
<span class="badge bg-primary bg-opacity-10 text-primary rounded-pill">Updated</span>
{% elif entry.action == 2 %}
<span class="badge bg-danger bg-opacity-10 text-danger rounded-pill">Deleted</span>
{% else %}
<span class="badge bg-secondary rounded-pill">Accessed</span>
{% endif %}
</td>
<td>
<span class="fw-medium">{{ entry.content_type.name|capfirst }}</span>
<br>
<small class="text-muted">{{ entry.object_repr }}</small>
</td>
<td class="small text-muted">
<div style="max-width: 400px; overflow-wrap: break-word;">
{% if entry.changes %}
{{ entry.changes|truncatechars:100 }}
{% else %}
-
{% endif %}
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="4" class="text-center py-5 text-muted">
<i class="bi bi-clock-history fs-1 d-block mb-3"></i>
No activity recorded yet.
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% if is_paginated %}
<div class="mt-4">
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link rounded-pill px-3 me-1" href="?page={{ page_obj.previous_page_number }}">Previous</a>
</li>
{% endif %}
<li class="page-item disabled">
<span class="page-link border-0 bg-transparent">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link rounded-pill px-3 ms-1" href="?page={{ page_obj.next_page_number }}">Next</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
{% endblock %}

View File

@ -5,7 +5,8 @@ from core.views import (
BookmarkListView, BookmarkCreateView, BookmarkDetailView, BookmarkListView, BookmarkCreateView, BookmarkDetailView,
BookmarkUpdateView, BookmarkDeleteView, BookmarkUpdateView, BookmarkDeleteView,
TeamListView, TeamDetailView, BookmarkShareToggleView, TeamListView, TeamDetailView, BookmarkShareToggleView,
BookmarkRegenerateView, SummaryUpdateView, ExtractionUpdateView BookmarkRegenerateView, SummaryUpdateView, ExtractionUpdateView,
UserActivityLogView
) )
router = DefaultRouter() router = DefaultRouter()
@ -26,6 +27,8 @@ urlpatterns = [
path("teams/", TeamListView.as_view(), name="team-list"), path("teams/", TeamListView.as_view(), name="team-list"),
path("teams/<int:pk>/", TeamDetailView.as_view(), name="team-detail"), path("teams/<int:pk>/", TeamDetailView.as_view(), name="team-detail"),
path("activity/", UserActivityLogView.as_view(), name="activity-log"),
path("api/status/", ApiStatusView.as_view(), name="api-status"), path("api/status/", ApiStatusView.as_view(), name="api-status"),
path("api/", include(router.urls)), path("api/", include(router.urls)),
] ]

View File

@ -8,6 +8,7 @@ from django.db import transaction
from django.http import JsonResponse, HttpResponseRedirect from django.http import JsonResponse, HttpResponseRedirect
from .models import Bookmark, Team, Extraction, BookmarkShare, Summary from .models import Bookmark, Team, Extraction, BookmarkShare, Summary
from .tasks import process_bookmark from .tasks import process_bookmark
from auditlog.models import LogEntry
class BookmarkListView(LoginRequiredMixin, ListView): class BookmarkListView(LoginRequiredMixin, ListView):
model = Bookmark model = Bookmark
@ -188,3 +189,12 @@ class BookmarkShareToggleView(LoginRequiredMixin, View):
shared = True shared = True
return JsonResponse({'shared': shared}) return JsonResponse({'shared': shared})
class UserActivityLogView(LoginRequiredMixin, ListView):
model = LogEntry
template_name = 'core/activity_log.html'
context_object_name = 'log_entries'
paginate_by = 20
def get_queryset(self):
return LogEntry.objects.filter(actor=self.request.user).select_related('content_type', 'actor').order_by('-timestamp')

View File

@ -11,3 +11,4 @@ redis==5.0.8
django-filter==24.3 django-filter==24.3
flower==2.0.1 flower==2.0.1
django-revproxy==0.11.0 django-revproxy==0.11.0
django-auditlog==3.4.1