| @ -1,46 +0,0 @@ | |||
| from django import forms | |||
| from django.contrib.auth.forms import UserCreationForm, UserChangeForm | |||
| from .models import Autor, Libro | |||
| class AutorForm(forms.ModelForm): | |||
| class Meta: | |||
| model = Autor | |||
| fields = ['nombre', 'biografia', 'foto'] | |||
| nombre = forms.CharField( | |||
| widget=forms.TextInput(attrs={'class': 'form-control'})) | |||
| biografia = forms.CharField( | |||
| widget=forms.TextInput(attrs={'class': 'form-control'})) | |||
| class LibroForm(forms.ModelForm): | |||
| class Meta: | |||
| model = Libro | |||
| fields = ['titulo', 'autor', 'fecha_publicacion', 'descripcion', | |||
| 'archivo', 'portada'] | |||
| titulo = forms.CharField( | |||
| widget=forms.TextInput(attrs={'class': 'form-control'})) | |||
| descripcion = forms.CharField( | |||
| widget=forms.TextInput(attrs={'class': 'form-control'})) | |||
| autor = forms.ModelChoiceField( | |||
| queryset=Autor.objects.all(), | |||
| widget=forms.Select(attrs={'class': 'form-control'})) | |||
| class ReyMotaUserCreationForm(UserCreationForm): | |||
| class Meta: | |||
| model = ReyMotaUser | |||
| fields = ("email", "nombre", "foto") | |||
| labels = {'email': 'Dirección de correo'} | |||
| class ReyMotaUserChangeForm(UserChangeForm): | |||
| class Meta: | |||
| model = ReyMotaUser | |||
| fields = ("email", "foto") | |||
| @ -1,35 +0,0 @@ | |||
| from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin | |||
| from django.db import models | |||
| import datetime | |||
| from django.core.validators import MaxValueValidator, MinValueValidator | |||
| from django.utils.translation import gettext_lazy as _ | |||
| def current_year(): | |||
| return datetime.date.today().year | |||
| def max_value_current_year(value): | |||
| return MaxValueValidator(current_year())(value) | |||
| class Autor(models.Model): | |||
| nombre = models.CharField(max_length=200) | |||
| biografia = models.TextField(blank=True, null=True) | |||
| foto = models.ImageField(upload_to='autores/', blank=True, null=True) # Nuevo campo | |||
| def __str__(self): | |||
| return self.nombre | |||
| class Libro(models.Model): | |||
| titulo = models.CharField(max_length=200) | |||
| autor = models.ForeignKey(Autor, on_delete=models.CASCADE) | |||
| fecha_publicacion = models.PositiveBigIntegerField(default=current_year(), validators=[MinValueValidator(1984), max_value_current_year]) | |||
| descripcion = models.TextField(blank=True, null=True) | |||
| archivo = models.FileField(upload_to='libros/') | |||
| portada = models.ImageField(upload_to='portadas/', blank=True, null=True) # Nuevo campo | |||
| def __str__(self): | |||
| return self.titulo | |||
| @ -1,20 +0,0 @@ | |||
| from django.urls import path | |||
| from . import views | |||
| app_name='libros' | |||
| urlpatterns = [ | |||
| path('autores/', views.lista_autores, name='lista_autores'), | |||
| path('autores/nuevo/', views.nuevo_autor, name='nuevo_autor'), | |||
| path('autores/<int:autor_id>/', views.detalle_autor, name='detalle_autor'), | |||
| path('autores/<int:autor_id>/editar/', views.editar_autor, name='editar_autor'), | |||
| path('autores/<int:autor_id>/eliminar/', views.eliminar_autor, name='eliminar_autor'), | |||
| path('libros/', views.lista_libros, name='lista_libros'), | |||
| path('libros/nuevo/', views.nuevo_libro, name='nuevo_libro'), | |||
| path('libros/<int:libro_id>/', views.detalle_libro, name='detalle_libro'), | |||
| path('libros/<int:libro_id>/editar/', views.editar_libro, name='editar_libro'), | |||
| path('libros/<int:libro_id>/eliminar/', views.eliminar_libro, name='eliminar_libro'), | |||
| ] | |||
| @ -1,113 +0,0 @@ | |||
| from django.shortcuts import render, get_object_or_404, redirect | |||
| from django.contrib.auth.decorators import login_required | |||
| from django.views.generic import CreateView | |||
| from django.contrib.auth.forms import UserCreationForm | |||
| from django.urls import reverse_lazy | |||
| from .models import Autor, Libro | |||
| from .forms import AutorForm, LibroForm | |||
| @login_required | |||
| def principal(request): | |||
| return render(request, 'gestion/index.html') | |||
| # Vistas para los autores | |||
| @login_required | |||
| def lista_autores(request): | |||
| autores = Autor.objects.all() | |||
| return render(request, 'gestion/lista_autores.html', {'autores': autores}) | |||
| @login_required | |||
| def detalle_autor(request, autor_id): | |||
| autor = get_object_or_404(Autor, pk=autor_id) | |||
| libros = Libro.objects.filter(autor=autor_id) | |||
| return render(request, 'gestion/detalle_autor.html', {'autor': autor, 'libros': libros}) | |||
| @login_required | |||
| def nuevo_autor(request): | |||
| if request.method == 'POST': | |||
| form = AutorForm(request.POST, request.FILES) | |||
| if form.is_valid(): | |||
| form.save() | |||
| return redirect('lista_autores') | |||
| else: | |||
| form = AutorForm() | |||
| return render(request, 'gestion/form_autor.html', {'form': form}) | |||
| @login_required | |||
| def editar_autor(request, autor_id): | |||
| autor = get_object_or_404(Autor, pk=autor_id) | |||
| if request.method == 'POST': | |||
| form = AutorForm(request.POST, request.FILES, instance=autor) | |||
| if form.is_valid(): | |||
| form.save() | |||
| return redirect('lista_autores') | |||
| else: | |||
| form = AutorForm(instance=autor) | |||
| return render(request, 'gestion/form_autor.html', {'form': form}) | |||
| @login_required | |||
| def eliminar_autor(request, autor_id): | |||
| autor = get_object_or_404(Autor, pk=autor_id) | |||
| autor.delete() | |||
| return redirect('lista_autores') | |||
| # Vistas para los libros | |||
| @login_required | |||
| def lista_libros(request): | |||
| libros = Libro.objects.all() | |||
| return render(request, 'gestion/lista_libros.html', {'libros': libros}) | |||
| @login_required | |||
| def detalle_libro(request, libro_id): | |||
| libro = get_object_or_404(Libro, pk=libro_id) | |||
| return render(request, 'gestion/detalle_libro.html', {'libro': libro}) | |||
| @login_required | |||
| def nuevo_libro(request): | |||
| if request.method == 'POST': | |||
| form = LibroForm(request.POST, request.FILES) | |||
| if form.is_valid(): | |||
| form.save() | |||
| return redirect('lista_libros') | |||
| else: | |||
| form = LibroForm() | |||
| return render(request, 'gestion/form_libro.html', {'form': form}) | |||
| @login_required | |||
| def editar_libro(request, libro_id): | |||
| libro = get_object_or_404(Libro, pk=libro_id) | |||
| if request.method == 'POST': | |||
| form = LibroForm(request.POST, request.FILES, instance=libro) | |||
| if form.is_valid(): | |||
| form.save() | |||
| return redirect('lista_libros') | |||
| else: | |||
| form = LibroForm(instance=libro) | |||
| return render(request, 'gestion/form_libro.html', {'form': form}) | |||
| @login_required | |||
| def eliminar_libro(request, libro_id): | |||
| libro = get_object_or_404(Libro, pk=libro_id) | |||
| libro.delete() | |||
| return redirect('lista_libros') | |||
| class SignUpView(CreateView): | |||
| form_class = UserCreationForm | |||
| success_url = reverse_lazy("login") | |||
| template_name = "registration/signup.html" | |||
| @ -1,19 +0,0 @@ | |||
| from django.urls import path | |||
| from . import views | |||
| app_name='repostajes' | |||
| urlpatterns = [ | |||
| path('vehiculos/', views.lista_vehiculos, name='lista_vehiculos'), | |||
| path('vehiculos/nuevo/', views.nuevo_vehiculo, name='nuevo_vehiculo'), | |||
| path('vehiculos/<int:vehiculo_id>/', views.detalle_vehiculo, name='detalle_vehiculo'), | |||
| path('vehiculos/<int:vehiculo_id>/editar/', views.editar_vehiculo, name='editar_vehiculo'), | |||
| path('vehiculos/<int:vehiculo_id>/eliminar/', views.eliminar_vehiculo, name='eliminar_vehiculo'), | |||
| path('repostajes/', views.lista_repostajes, name='lista_repostajes'), | |||
| path('repostajes/nuevo/', views.nuevo_repostaje, name='nuevo_repostaje'), | |||
| path('repostajes/<int:repostaje_id>/', views.detalle_repostaje, name='detalle_repostaje'), | |||
| path('repostajes/<int:repostaje_id>/editar/', views.editar_repostaje, name='editar_repostaje'), | |||
| path('repostajes/<int:repostaje_id>/eliminar/', views.eliminar_repostaje, name='eliminar_repostaje'), | |||
| ] | |||
| @ -1,146 +0,0 @@ | |||
| """ | |||
| Django settings for reymota project. | |||
| Generated by 'django-admin startproject' using Django 5.1. | |||
| For more information on this file, see | |||
| https://docs.djangoproject.com/en/5.1/topics/settings/ | |||
| For the full list of settings and their values, see | |||
| https://docs.djangoproject.com/en/5.1/ref/settings/ | |||
| """ | |||
| from pathlib import Path | |||
| # Build paths inside the project like this: BASE_DIR / 'subdir'. | |||
| BASE_DIR = Path(__file__).resolve().parent.parent | |||
| # Quick-start development settings - unsuitable for production | |||
| # See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ | |||
| # SECURITY WARNING: keep the secret key used in production secret! | |||
| SECRET_KEY = 'django-insecure-vu#zk4g8pj-qoov#8^i$&s8n_ipp2r3h+o$z1w(1%d=6+i@erm' | |||
| # SECURITY WARNING: don't run with debug turned on in production! | |||
| DEBUG = True | |||
| ALLOWED_HOSTS = [] | |||
| # Application definition | |||
| INSTALLED_APPS = [ | |||
| 'django.contrib.admin', | |||
| 'django.contrib.auth', | |||
| 'django.contrib.contenttypes', | |||
| 'django.contrib.sessions', | |||
| 'django.contrib.messages', | |||
| 'django.contrib.staticfiles', | |||
| 'repostajes', | |||
| 'reymotausers', | |||
| ] | |||
| MIDDLEWARE = [ | |||
| 'django.middleware.security.SecurityMiddleware', | |||
| 'django.contrib.sessions.middleware.SessionMiddleware', | |||
| 'django.middleware.common.CommonMiddleware', | |||
| 'django.middleware.csrf.CsrfViewMiddleware', | |||
| 'django.contrib.auth.middleware.AuthenticationMiddleware', | |||
| 'django.contrib.messages.middleware.MessageMiddleware', | |||
| 'django.middleware.clickjacking.XFrameOptionsMiddleware', | |||
| ] | |||
| ROOT_URLCONF = 'reymota.urls' | |||
| TEMPLATES = [ | |||
| { | |||
| 'BACKEND': 'django.template.backends.django.DjangoTemplates', | |||
| 'DIRS': [ BASE_DIR / 'templates' ], | |||
| 'APP_DIRS': True, | |||
| 'OPTIONS': { | |||
| 'context_processors': [ | |||
| 'django.template.context_processors.debug', | |||
| 'django.template.context_processors.request', | |||
| 'django.contrib.auth.context_processors.auth', | |||
| 'django.contrib.messages.context_processors.messages', | |||
| ], | |||
| 'libraries': { | |||
| 'filtros_de_entorno': 'reymota.templatetags.filtros_de_entorno', | |||
| } | |||
| }, | |||
| }, | |||
| ] | |||
| WSGI_APPLICATION = 'reymota.wsgi.application' | |||
| # Database | |||
| # https://docs.djangoproject.com/en/5.1/ref/settings/#databases | |||
| DATABASES = { | |||
| 'default': { | |||
| 'ENGINE': 'django.db.backends.sqlite3', | |||
| 'NAME': BASE_DIR / 'db.sqlite3', | |||
| } | |||
| } | |||
| # Password validation | |||
| # https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators | |||
| AUTH_PASSWORD_VALIDATORS = [ | |||
| { | |||
| 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', | |||
| }, | |||
| { | |||
| 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', | |||
| }, | |||
| { | |||
| 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', | |||
| }, | |||
| { | |||
| 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', | |||
| }, | |||
| ] | |||
| # Internationalization | |||
| # https://docs.djangoproject.com/en/5.1/topics/i18n/ | |||
| LANGUAGE_CODE = 'es-es' | |||
| TIME_ZONE = 'Europe/Madrid' | |||
| USE_I18N = True | |||
| USE_TZ = True | |||
| I18N = True | |||
| L10N = True | |||
| DECIMAL_SEPARATOR = ',' | |||
| THOUSAND_SEPARATOR = '.' | |||
| # Static files (CSS, JavaScript, Images) | |||
| # https://docs.djangoproject.com/en/5.1/howto/static-files/ | |||
| STATIC_URL = '/static/' | |||
| STATIC_ROOT = BASE_DIR / "staticfiles" | |||
| # Default primary key field type | |||
| # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field | |||
| DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' | |||
| LOGIN_URL = '/accounts/login/' | |||
| LOGIN_REDIRECT_URL = 'principal' | |||
| LOGOUT_REDIRECT_URL = 'principal' | |||
| AUTH_USER_MODEL = "reymotausers.ReyMotaUser" | |||
| MEDIA_ROOT = BASE_DIR / "mediafiles" | |||
| MEDIA_URL = '/media/' | |||
| if DEBUG is False: | |||
| CSRF_TRUSTED_ORIGINS = os.environ.get("CSRF_TRUSTED_ORIGINS").split(" ") | |||
| @ -1,37 +0,0 @@ | |||
| """ | |||
| URL configuration for reymota project. | |||
| The `urlpatterns` list routes URLs to views. For more information please see: | |||
| https://docs.djangoproject.com/en/5.1/topics/http/urls/ | |||
| Examples: | |||
| Function views | |||
| 1. Add an import: from my_app import views | |||
| 2. Add a URL to urlpatterns: path('', views.home, name='home') | |||
| Class-based views | |||
| 1. Add an import: from other_app.views import Home | |||
| 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') | |||
| Including another URLconf | |||
| 1. Import the include() function: from django.urls import include, path | |||
| 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) | |||
| """ | |||
| from django.contrib import admin | |||
| from django.urls import path, include | |||
| from django.conf.urls.static import static | |||
| from django.conf import settings | |||
| from django.views.generic.base import TemplateView # new | |||
| urlpatterns = [ | |||
| path('obreros/', admin.site.urls), | |||
| # path('apuntes/', include('apuntes.urls')), | |||
| path('repostajes/', include('repostajes.urls')), | |||
| path("accounts/", include("accounts.urls")), # new | |||
| path("accounts/", include("django.contrib.auth.urls")), | |||
| path("", TemplateView.as_view(template_name="apuntes/index.html"), | |||
| name="principal"), # new | |||
| ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) | |||
| @ -1,121 +0,0 @@ | |||
| {% load static %} | |||
| <header class="app-header fixed-top"> | |||
| <div class="app-header-inner"> | |||
| <div class="container-fluid py-2"> | |||
| <div class="app-header-content"> | |||
| <div class="row justify-content-between align-items-center"> | |||
| <div class="col-auto"> | |||
| <a id="sidepanel-toggler" class="sidepanel-toggler d-inline-block d-xl-none" href="#"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" role="img"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg> | |||
| </a> | |||
| </div><!--//col--> | |||
| <div class="app-utilities col-auto"> | |||
| <div class="app-utility-item"> | |||
| <a href="settings.html" title="Settings"> | |||
| <!--//Bootstrap Icons: https://icons.getbootstrap.com/ --> | |||
| <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-gear icon" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M8.837 1.626c-.246-.835-1.428-.835-1.674 0l-.094.319A1.873 1.873 0 0 1 4.377 3.06l-.292-.16c-.764-.415-1.6.42-1.184 1.185l.159.292a1.873 1.873 0 0 1-1.115 2.692l-.319.094c-.835.246-.835 1.428 0 1.674l.319.094a1.873 1.873 0 0 1 1.115 2.693l-.16.291c-.415.764.42 1.6 1.185 1.184l.292-.159a1.873 1.873 0 0 1 2.692 1.116l.094.318c.246.835 1.428.835 1.674 0l.094-.319a1.873 1.873 0 0 1 2.693-1.115l.291.16c.764.415 1.6-.42 1.184-1.185l-.159-.291a1.873 1.873 0 0 1 1.116-2.693l.318-.094c.835-.246.835-1.428 0-1.674l-.319-.094a1.873 1.873 0 0 1-1.115-2.692l.16-.292c.415-.764-.42-1.6-1.185-1.184l-.291.159A1.873 1.873 0 0 1 8.93 1.945l-.094-.319zm-2.633-.283c.527-1.79 3.065-1.79 3.592 0l.094.319a.873.873 0 0 0 1.255.52l.292-.16c1.64-.892 3.434.901 2.54 2.541l-.159.292a.873.873 0 0 0 .52 1.255l.319.094c1.79.527 1.79 3.065 0 3.592l-.319.094a.873.873 0 0 0-.52 1.255l.16.292c.893 1.64-.902 3.434-2.541 2.54l-.292-.159a.873.873 0 0 0-1.255.52l-.094.319c-.527 1.79-3.065 1.79-3.592 0l-.094-.319a.873.873 0 0 0-1.255-.52l-.292.16c-1.64.893-3.433-.902-2.54-2.541l.159-.292a.873.873 0 0 0-.52-1.255l-.319-.094c-1.79-.527-1.79-3.065 0-3.592l.319-.094a.873.873 0 0 0 .52-1.255l-.16-.292c-.892-1.64.902-3.433 2.541-2.54l.292.159a.873.873 0 0 0 1.255-.52l.094-.319z"/> | |||
| <path fill-rule="evenodd" d="M8 5.754a2.246 2.246 0 1 0 0 4.492 2.246 2.246 0 0 0 0-4.492zM4.754 8a3.246 3.246 0 1 1 6.492 0 3.246 3.246 0 0 1-6.492 0z"/> | |||
| </svg> | |||
| </a> | |||
| </div><!--//app-utility-item--> | |||
| <div class="app-utility-item app-user-dropdown dropdown"> | |||
| {% if user.is_authenticated %} | |||
| <a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><img src=" {{user.foto.url }}"></a> | |||
| {% else %} | |||
| <a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Sin usuario</a> | |||
| {% endif %} | |||
| <ul class="dropdown-menu" aria-labelledby="user-dropdown-toggle"> | |||
| {% if user.is_authenticated %} | |||
| <li> | |||
| <a class="dropdown-item">{{ user.nombre }}</a> | |||
| </li> | |||
| <li><a class="dropdown-item"> | |||
| <form method="post" action="{% url 'logout' %}" > | |||
| {% csrf_token %} | |||
| <button | |||
| style="background: none!important; | |||
| border: none; | |||
| padding: 0!important; | |||
| /*optional*/ | |||
| font-family: arial, sans-serif; | |||
| /*input has OS specific font-family*/ | |||
| /*color: #069; | |||
| text-decoration: underline;*/ | |||
| cursor: pointer;" | |||
| type="submit">Salir</button> | |||
| </form></a> | |||
| </li> | |||
| {% else %} | |||
| <li><a class="dropdown-item" href="{% url 'login' %}">Entrar</a></li> | |||
| {% endif %} | |||
| </ul> | |||
| </div><!--//app-user-dropdown--> | |||
| </div><!--//app-utilities--> | |||
| </div><!--//row--> | |||
| </div><!--//app-header-content--> | |||
| </div><!--//container-fluid--> | |||
| </div><!--//app-header-inner--> | |||
| <div id="app-sidepanel" class="app-sidepanel"> | |||
| <div id="sidepanel-drop" class="sidepanel-drop"></div> | |||
| <div class="sidepanel-inner d-flex flex-column"> | |||
| <a href="#" id="sidepanel-close" class="sidepanel-close d-xl-none">×</a> | |||
| {% include "_branding.html" %} | |||
| <nav id="app-nav-main" class="app-nav app-nav-main flex-grow-1"> | |||
| <ul class="app-menu list-unstyled accordion" id="menu-accordion"> | |||
| <li class="nav-item"> | |||
| <!--//Bootstrap Icons: https://icons.getbootstrap.com/ --> | |||
| <a class="nav-link active" href="{% url 'principal' %}"> | |||
| <span class="nav-icon"> | |||
| <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-house-door" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M7.646 1.146a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 .146.354v7a.5.5 0 0 1-.5.5H9.5a.5.5 0 0 1-.5-.5v-4H7v4a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .146-.354l6-6zM2.5 7.707V14H6v-4a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 .5.5v4h3.5V7.707L8 2.207l-5.5 5.5z"/> | |||
| <path fill-rule="evenodd" d="M13 2.5V6l-2-2V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5z"/> | |||
| </svg> | |||
| </span> | |||
| <span class="nav-link-text">Principal</span> | |||
| </a><!--//nav-link--> | |||
| </li><!--//nav-item--> | |||
| {% if user.is_authenticated %} | |||
| <li class="nav-item has-submenu"> | |||
| <!--//Bootstrap Icons: https://icons.getbootstrap.com/ --> | |||
| <a class="nav-link submenu-toggle" href="#" data-bs-toggle="collapse" data-bs-target="#submenu-1" aria-expanded="false" aria-controls="submenu-1"> | |||
| <span class="nav-icon"> | |||
| <!--//Bootstrap Icons: https://icons.getbootstrap.com/ --> | |||
| <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-files" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M4 2h7a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zm0 1a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H4z"/> | |||
| <path d="M6 0h7a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2v-1a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H6a1 1 0 0 0-1 1H4a2 2 0 0 1 2-2z"/> | |||
| </svg> | |||
| </span> | |||
| <span class="nav-link-text">Aplicaciones</span> | |||
| <span class="submenu-arrow"> | |||
| <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-chevron-down" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/> | |||
| </svg> | |||
| </span><!--//submenu-arrow--> | |||
| </a><!--//nav-link--> | |||
| <div id="submenu-1" class="collapse submenu submenu-1" data-bs-parent="#menu-accordion"> | |||
| <ul class="submenu-list list-unstyled"> | |||
| <li class="submenu-item"><a class="submenu-link" href="{% url 'libros:principal' %}">Libros</a></li> | |||
| <li class="submenu-item"><a class="submenu-link" href="{% url 'repostajes:principal' %}">Vehiculos</a></li> | |||
| </ul> | |||
| </div> | |||
| </li><!--//nav-item--> | |||
| {% endif %} | |||
| </ul><!--//app-menu--> | |||
| </nav><!--//app-nav--> | |||
| </div><!--//sidepanel-inner--> | |||
| </div><!--//app-sidepanel--> | |||
| </header><!--//app-header--> | |||
| @ -1,23 +0,0 @@ | |||
| {% load static %} | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <title>Aplicaciones en Reymota.es</title> | |||
| <!-- Meta --> | |||
| <meta charset="utf-8"> | |||
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
| <meta name="description" content="Portal - Bootstrap 5 Admin Dashboard Template For Developers"> | |||
| <meta name="author" content="Celestino Rey" > | |||
| <link rel="shortcut icon" href="{% static 'images/favicon.ico' %}"> | |||
| <!-- FontAwesome JS--> | |||
| <script defer src="{% static 'plugins/fontawesome/js/all.min.js' %}"></script> | |||
| <!-- App CSS --> | |||
| <link id="theme-style" rel="stylesheet" href="{% static 'css/portal.css' %}"> | |||
| </head> | |||
| @ -1,55 +0,0 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| <div class="container-xl"> | |||
| <h1 class="app-page-title">Introducción</h1> | |||
| <div class="app-card alert alert-dismissible shadow-sm mb-4 border-left-decoration" role="alert"> | |||
| <div class="inner"> | |||
| <div class="app-card-body p-3 p-lg-4"> | |||
| <h3 class="mb-3">¡Bienvenido a la colección de libros!</h3> | |||
| <div class="row gx-5 gy-3"> | |||
| <!-- | |||
| <div class="col-12 col-lg-9"> | |||
| <div>Pensado inicialmente para guardar las letras de las canciones de Bruce Springsteen.</div> | |||
| </div>--><!--//col--> | |||
| </div><!--//row--> | |||
| <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> | |||
| </div><!--//app-card-body--> | |||
| </div><!--//inner--> | |||
| </div><!--//app-card--> | |||
| <div class="row g-4 mb-4"> | |||
| <div class="col-6 col-lg-3"> | |||
| <div class="app-card app-card-stat shadow-sm h-100"> | |||
| <div class="app-card-body p-3 p-lg-4"> | |||
| <h4 class="stats-type mb-1">Vehículos</h4> | |||
| <div class="stats-figure">$12,628</div> | |||
| <div class="stats-meta text-success"> | |||
| <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-arrow-up" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M8 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L7.5 2.707V14.5a.5.5 0 0 0 .5.5z"/> | |||
| </svg> 20%</div> | |||
| </div><!--//app-card-body--> | |||
| <a class="app-card-link-mask" href="{% url 'libros:lista_vehiculos' %}"></a> | |||
| </div><!--//app-card--> | |||
| </div><!--//col--> | |||
| <div class="col-6 col-lg-3"> | |||
| <div class="app-card app-card-stat shadow-sm h-100"> | |||
| <div class="app-card-body p-3 p-lg-4"> | |||
| <h4 class="stats-type mb-1">Repostajes</h4> | |||
| <div class="stats-figure">$2,250</div> | |||
| <div class="stats-meta text-success"> | |||
| <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-arrow-down" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z"/> | |||
| </svg> 5% </div> | |||
| </div><!--//app-card-body--> | |||
| <a class="app-card-link-mask" href="{% url 'libros:lista_repostajes' %}"></a> | |||
| </div><!--//app-card--> | |||
| </div><!--//col--> | |||
| </div><!--//row--> | |||
| </div><!--//container-fluid--> | |||
| {% endblock %} | |||
| @ -1,71 +0,0 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| <div class="container-xl"> | |||
| <div class="row g-3 mb-4 align-items-center justify-content-between"> | |||
| <div class="col-auto"> | |||
| <h1 class="app-page-title mb-0">Autores</h1> | |||
| </div> | |||
| </div><!--//row--> | |||
| <div class="col-auto"> | |||
| <div class="page-utilities"> | |||
| <div class="row g-4 justify-content-start justify-content-md-end align-items-center"> | |||
| <div class="col-auto"> | |||
| <a class="btn app-btn-primary" href="{% url 'nuevo_autor' %}">Añadir autor</a> | |||
| </div> | |||
| </div><!--//row--> | |||
| </div><!--//table-utilities--> | |||
| </div><!--//col-auto--> | |||
| <div class="row g-4"> | |||
| {% for autor in autores %} | |||
| <div class="col-6 col-md-4 col-xl-3 col-xxl-2"> | |||
| <div class="app-card app-card-doc shadow-sm h-100"> | |||
| <div class="app-card-body p-3 has-card-actions"> | |||
| {% if autor.foto %} | |||
| <img src="{{ autor.foto.url }}" alt="Foto del autor" style="width:200px;height:200px;"> | |||
| {% else %} | |||
| Sin imágen | |||
| {% endif %} | |||
| <h4 class="app-doc-title truncate mb-0"><a href="{% url 'detalle_autor' autor.id %}">{{ autor.nombre}}</a></h4> | |||
| <div class="app-card-actions"> | |||
| <div class="dropdown"> | |||
| <div class="dropdown-toggle no-toggle-arrow" data-bs-toggle="dropdown" aria-expanded="false"> | |||
| <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-three-dots-vertical" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/> | |||
| </svg> | |||
| </div><!--//dropdown-toggle--> | |||
| <ul class="dropdown-menu"> | |||
| <li><a class="dropdown-item" href="{% url 'detalle_autor' autor.id %}"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-eye me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.134 13.134 0 0 0 1.66 2.043C4.12 11.332 5.88 12.5 8 12.5c2.12 0 3.879-1.168 5.168-2.457A13.134 13.134 0 0 0 14.828 8a13.133 13.133 0 0 0-1.66-2.043C11.879 4.668 10.119 3.5 8 3.5c-2.12 0-3.879 1.168-5.168 2.457A13.133 13.133 0 0 0 1.172 8z"/> | |||
| <path fill-rule="evenodd" d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/> | |||
| </svg>Ver</a></li> | |||
| <li><a class="dropdown-item" href="{% url 'editar_autor' autor.id %}"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-pencil me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5L13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175l-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/> | |||
| </svg>Editar</a></li> | |||
| <li><a class="dropdown-item" href="{% url 'eliminar_autor' autor.id %}"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-download me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/> | |||
| <path fill-rule="evenodd" d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/> | |||
| </svg>Eliminar</a></li> | |||
| <!-- | |||
| <li><hr class="dropdown-divider"></li> | |||
| <li><a class="dropdown-item" href="#"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-trash me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/> | |||
| <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4L4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/> | |||
| </svg>Delete</a></li> | |||
| --> | |||
| </ul> | |||
| </div><!--//dropdown--> | |||
| </div><!--//app-card-actions--> | |||
| </div><!--//app-card-body--> | |||
| </div> | |||
| </div> | |||
| {% endfor %} | |||
| </div> | |||
| </div><!--//container-fluid--> | |||
| {% endblock %} | |||
| @ -1,72 +0,0 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| <div class="container-xl"> | |||
| <div class="row g-3 mb-4 align-items-center justify-content-between"> | |||
| <div class="col-auto"> | |||
| <h1 class="app-page-title mb-0">Libros</h1> | |||
| </div> | |||
| </div><!--//row--> | |||
| <div class="col-auto"> | |||
| <div class="page-utilities"> | |||
| <div class="row g-4 justify-content-start justify-content-md-end align-items-center"> | |||
| <div class="col-auto"> | |||
| <a class="btn app-btn-primary" href="{% url 'nuevo_libro' %}">Añadir libro</a> | |||
| </div> | |||
| </div><!--//row--> | |||
| </div><!--//table-utilities--> | |||
| </div><!--//col-auto--> | |||
| <div class="row g-4"> | |||
| {% for libro in libros %} | |||
| <div class="col-6 col-md-4 col-xl-3 col-xxl-2"> | |||
| <div class="app-card app-card-doc shadow-sm h-100"> | |||
| <div class="app-card-body p-3 has-card-actions"> | |||
| {% if libro.portada %} | |||
| <a><img src="{{ libro.portada.url }}" alt="{{ libro.titulo }}," style="width:50px;height:50px;"></a> | |||
| {% else %} | |||
| Sin imágen | |||
| {% endif %} | |||
| <h4 class="app-doc-title truncate mb-0"><a href="{% url 'detalle_libro' libro.id %}">{{ libro.titulo }}</a></h4> | |||
| <div class="app-doc-meta"> | |||
| <ul class="list-unstyled mb-0"> | |||
| <li><span class="text-muted">Autor: </span><a href="{% url 'detalle_autor' libro.autor.id %}">{{ libro.autor.nombre }}</a></li> | |||
| </ul> | |||
| </div><!--//app-doc-meta--> | |||
| <div class="app-card-actions"> | |||
| <div class="dropdown"> | |||
| <div class="dropdown-toggle no-toggle-arrow" data-bs-toggle="dropdown" aria-expanded="false"> | |||
| <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-three-dots-vertical" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/> | |||
| </svg> | |||
| </div><!--//dropdown-toggle--> | |||
| <ul class="dropdown-menu"> | |||
| <li><a class="dropdown-item" href="{% url 'editar_libro' libro.id %}"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-pencil me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5L13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175l-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/> | |||
| </svg>Editar</a></li> | |||
| <li><a class="dropdown-item" href="{{ libro.archivo.url }}"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-download me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path fill-rule="evenodd" d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/> | |||
| <path fill-rule="evenodd" d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/> | |||
| </svg>Descargar</a></li> | |||
| <!-- | |||
| <li><hr class="dropdown-divider"></li> | |||
| <li><a class="dropdown-item" href="#"><svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-trash me-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/> | |||
| <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4L4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/> | |||
| </svg>Delete</a></li> | |||
| --> | |||
| </ul> | |||
| </div><!--//dropdown--> | |||
| </div><!--//app-card-actions--> | |||
| </div><!--//app-card-body--> | |||
| </div> | |||
| </div> | |||
| {% endfor %} | |||
| </div> | |||
| </div><!--//container-fluid--> | |||
| {% endblock %} | |||