Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 44 additions & 36 deletions Templates/Details/details_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,7 @@ <h4>{% trans "Deja tu opinión" %}</h4>
if (favoriteBtn) {
favoriteBtn.addEventListener('click', function() {
const targetUrl = this.getAttribute('data-url');

const csrftoken = getCookie('csrftoken'); // Obtenemos el token real
const csrftoken = getCookie('csrftoken');

fetch(targetUrl, {
method: 'POST',
Expand All @@ -175,41 +174,50 @@ <h4>{% trans "Deja tu opinión" %}</h4>
});
}

const platformButtons = document.querySelectorAll('.track-platform-btn');
const toast = document.getElementById('history-toast');

platformButtons.forEach(btn => {
btn.addEventListener('click', function() {
const contingutId = this.getAttribute('data-contingut-id');
const apiId = this.getAttribute('data-api-id');

const csrftoken = getCookie('csrftoken'); // Obtenemos el token real

fetch("{% url 'register_platform_click' %}", {
method: 'POST',
headers: {
'X-CSRFToken': csrftoken,
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({ contingut_id: contingutId, api_id: apiId })
})
.then(response => {
if (!response.ok) throw new Error('Error en el registro del clic');
return response.json();
})
.then(data => {
if (data.status === 'success') {
// Solo disparamos el Toast verde de confirmación
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
})
.catch(error => console.error('Error tracking click:', error));
// 2. Lógica de plataformas según si el usuario está logueado o no
{% if user.is_authenticated %}
// Si ESTÁ logueado: Rastreamos el clic y mostramos el Toast
const platformButtons = document.querySelectorAll('.track-platform-btn');
const toast = document.getElementById('history-toast');

platformButtons.forEach(btn => {
btn.addEventListener('click', function() {
const contingutId = this.getAttribute('data-contingut-id');
const apiId = this.getAttribute('data-api-id');
const csrftoken = getCookie('csrftoken');

fetch("{% url 'register_platform_click' %}", {
method: 'POST',
headers: {
'X-CSRFToken': csrftoken,
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({ contingut_id: contingutId, api_id: apiId })
})
.then(response => {
if (!response.ok) throw new Error('Error en el registro del clic');
return response.json();
})
.then(data => {
if (data.status === 'success') {
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
})
.catch(error => console.error('Error tracking click:', error));
});
});
{% else %}
const platformButtons = document.querySelectorAll('.track-platform-btn');
platformButtons.forEach(btn => {
btn.addEventListener('click', function() {
window.location.href = "{% url 'login' %}";
});
});
});
{% endif %}
});
</script>
{% endblock %}
44 changes: 44 additions & 0 deletions Templates/paginator.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{% load i18n %}

<nav aria-label="Page navigation">
<ul class="pagination justify-content-center mb-0 custom-pagination">
{% if items.has_previous %}
<li class="page-item">
<a class="page-link text-white-50 bg-transparent border-secondary" href="?page=1{% if request.GET.platform %}&platform={{ request.GET.platform }}{% endif %}{% if request.GET.date %}&date={{ request.GET.date }}{% endif %}" aria-label="{% trans 'Primera' %}">
<span aria-hidden="true">&laquo;&laquo;</span>
</a>
</li>
<li class="page-item">
<a class="page-link text-white-50 bg-transparent border-secondary" href="?page={{ items.previous_page_number }}{% if request.GET.platform %}&platform={{ request.GET.platform }}{% endif %}{% if request.GET.date %}&date={{ request.GET.date }}{% endif %}" aria-label="{% trans 'Anterior' %}">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
{% endif %}

<li class="page-item active" aria-current="page">
<span class="page-link text-neon bg-dark border-secondary" style="border-color: var(--neon-cyan) !important;">
{% trans "Pàgina" %} {{ items.number }} {% trans "de" %} {{ items.paginator.num_pages }}
</span>
</li>

{% if items.has_next %}
<li class="page-item">
<a class="page-link text-white-50 bg-transparent border-secondary" href="?page={{ items.next_page_number }}{% if request.GET.platform %}&platform={{ request.GET.platform }}{% endif %}{% if request.GET.date %}&date={{ request.GET.date }}{% endif %}" aria-label="{% trans 'Següent' %}">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
<li class="page-item">
<a class="page-link text-white-50 bg-transparent border-secondary" href="?page={{ items.paginator.num_pages }}{% if request.GET.platform %}&platform={{ request.GET.platform }}{% endif %}{% if request.GET.date %}&date={{ request.GET.date }}{% endif %}" aria-label="{% trans 'Última' %}">
<span aria-hidden="true">&raquo;&raquo;</span>
</a>
</li>
{% endif %}
</ul>
</nav>

<style>
.custom-pagination .page-link:hover {
background-color: rgba(102, 252, 241, 0.1) !important;
color: var(--neon-cyan) !important;
}
</style>
1 change: 1 addition & 0 deletions users/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __call__(self, request):
'update_user_role',
'gestion_cartelleres',
'editar_cartellera',
'system_logs',
]

if current_url_name not in exempt_url_names and not request.path.startswith('/static/'):
Expand Down
78 changes: 78 additions & 0 deletions users/templates/users/parts/system_logs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{% extends 'users/types/staff_admin.html' %}
{% load i18n %}

{% block staff_admin_content %}
<div class="container-fluid mt-4">
<div class="row mb-4 align-items-center">
<div class="col">
<h2 class="h3 mb-0 text-white" style="font-family: 'Syne', sans-serif;">{% trans "Logs de Sincronización" %}</h2>
<p class="text-muted small">{% trans "Registro histórico del Scheduler con las APIs externas." %}</p>
</div>
</div>

<div class="glass-card overflow-hidden">
<div class="table-responsive">
<table class="table table-dark table-hover mb-0 align-middle custom-table">
<thead>
<tr>
<th scope="col">{% trans "Fecha de Inicio" %}</th>
<th scope="col">{% trans "Fecha Fin" %}</th>
<th scope="col">{% trans "Estado" %}</th>
<th scope="col">{% trans "Resumen" %}</th>
</tr>
</thead>
<tbody>
{% for log in logs %}
<tr>
<td class="text-white-50">
<i class="bi bi-clock-history me-2"></i>{{ log.start_time|date:"d M Y, H:i:s" }}
</td>
<td class="text-white-50">
{% if log.end_time %}
{{ log.end_time|date:"d M Y, H:i:s" }}
{% else %}
<span class="text-muted">{% trans "En curso..." %}</span>
{% endif %}
</td>
<td>
{% if log.status == 'SUCCESS' %}
<span class="badge bg-success bg-opacity-25 text-success border border-success border-opacity-25 px-2 py-1 rounded-pill">
<i class="bi bi-check-circle me-1"></i> Éxito
</span>
{% elif log.status == 'ERROR' %}
<span class="badge bg-danger bg-opacity-25 text-danger border border-danger border-opacity-25 px-2 py-1 rounded-pill">
<i class="bi bi-exclamation-triangle me-1"></i> Error
</span>
{% else %}
<span class="badge bg-warning bg-opacity-25 text-warning border border-warning border-opacity-25 px-2 py-1 rounded-pill">
<i class="bi bi-arrow-repeat me-1"></i> {{ log.status }}
</span>
{% endif %}
</td>
<td class="text-white-50 small">
{% if log.summary %}
{{ log.summary|truncatechars:80 }}
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="4" class="text-center py-4 text-muted">
{% trans "Todavía no hay ningún registro de sincronización." %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>

{% if logs.has_other_pages %}
<div class="mt-4">
{% include 'paginator.html' with items=logs %}
</div>
{% endif %}
</div>
{% endblock %}
8 changes: 6 additions & 2 deletions users/templates/users/types/staff_admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@
<a class="nav-link {% if request.resolver_match.url_name == 'gestion_cartelleres' or request.resolver_match.url_name == 'editar_cartellera' %}active{% endif %}"
href="{% url 'gestion_cartelleres' %}"><i class="bi bi-images me-1"></i>{% trans 'Carteleras' %}</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.resolver_match.url_name == 'system_logs' %}active{% endif %}"
href="{% url 'system_logs' %}"><i class="bi bi-terminal-fill me-1"></i>{% trans 'Logs del Sistema' %}</a>
</li>
</ul>

<div class="tab-content-area">
<div class="tab-content-area mt-3">
{% block staff_admin_content %}{% endblock %}
</div>

{% endblock %}
{% endblock %}
3 changes: 2 additions & 1 deletion users/urls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.urls import path
from . import views
from web_app.views import system_logs

urlpatterns = [
# Staff Admin URLs
Expand All @@ -10,7 +11,7 @@
path('api/update-role/', views.update_user_role, name='update_user_role'),
path('staff-admin/cartelleres/', views.gestion_cartelleres, name='gestion_cartelleres'),
path('staff-admin/cartelleres/editar/<int:contingut_id>/', views.editar_cartellera, name='editar_cartellera'),

path('staff-admin/logs/', system_logs, name='system_logs'),
# User URLs
path('profile/', views.user_profile, name='user_profile'),
path('history/', views.history, name='history'),
Expand Down
1 change: 1 addition & 0 deletions users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,3 +480,4 @@ def editar_cartellera(request, contingut_id):
return render(request, 'users/parts/editar_cartellera.html', {
'contingut': contingut,
})

15 changes: 14 additions & 1 deletion web_app/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.shortcuts import render, redirect, get_object_or_404
from web_app.forms import CustomUserAdminCreationForm, CustomUserCreationForm
from web_app.models import AgeRating, API, CustomUser, Director, Genre, Movie, UserProfile, Series, Contingut, \
AgeRating, Valoracio, Visualitzacio
AgeRating, Valoracio, Visualitzacio, SyncLog
from web_app import utils
import json
from itertools import chain
Expand Down Expand Up @@ -266,3 +266,16 @@ def register_platform_click(request):

return JsonResponse({'status': 'error', 'message': 'Método no permitido'}, status=405)


@user_passes_test(lambda u: u.is_superuser)
def system_logs(request):
if not request.user.is_authenticated:
return redirect('login')

logs = SyncLog.objects.all().order_by('-start_time')
paginator = Paginator(logs, 20)
page_obj = paginator.get_page(request.GET.get('page', 1))

return render(request, 'users/parts/system_logs.html', {
'logs': page_obj
})
Loading