| @ -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 %} | |||||