| @ -0,0 +1,50 @@ | |||
| export ARQUITECTURA := $(shell lscpu |grep itectur | tr -d ' '| cut -f2 -d':') | |||
| #export REGISTRY=registry.cube.local | |||
| export REGISTRY=registry.reymota.es | |||
| export IMG_VERSION = 0.16 | |||
| export IMG_NGINX_VERSION = 1.0 | |||
| # limpia todo | |||
| all: imagen clean install | |||
| imagen: | |||
| cd ../; make | |||
| install: | |||
| -kubectl create -f namespace.yaml | |||
| -kubectl create -f reg-secret.yaml | |||
| -kubectl create -f env-prod-configmap.yaml | |||
| -kubectl create -f env-prod-db-configmap.yaml | |||
| -kubectl create -f pv-local-reymota.yaml | |||
| -kubectl create -f reymota-prod-persistentvolumeclaim.yaml | |||
| -kubectl create -f static-volume-persistentvolumeclaim.yaml | |||
| -kubectl create -f postgres-data-persistentvolumeclaim.yaml | |||
| -kubectl create -f db-deployment.yaml | |||
| -kubectl create -f db-service.yaml | |||
| -envsubst < reymota-deployment.yaml |kubectl create -f - | |||
| -envsubst < nginx-deployment.yaml |kubectl create -f - | |||
| -kubectl create -f nginx-service.yaml | |||
| clean: | |||
| -envsubst < nginx-deployment.yaml |kubectl delete -f - | |||
| -kubectl delete -f nginx-service.yaml | |||
| -envsubst < reymota-deployment.yaml |kubectl delete -f - | |||
| -kubectl delete -f db-deployment.yaml | |||
| -kubectl delete -f db-service.yaml | |||
| -kubectl delete -f env-prod-configmap.yaml | |||
| -kubectl delete -f env-prod-db-configmap.yaml | |||
| -kubectl delete -f postgres-data-persistentvolumeclaim.yaml | |||
| -kubectl delete -f static-volume-persistentvolumeclaim.yaml | |||
| -kubectl delete -f reymota-prod-persistentvolumeclaim.yaml | |||
| -kubectl delete -f pv-local-reymota.yaml | |||
| -kubectl delete -f reg-secret.yaml | |||
| -kubectl delete -f namespace.yaml | |||
| nginx: | |||
| cd ../nginx; make | |||
| @ -0,0 +1,52 @@ | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: db | |||
| name: db | |||
| namespace: reymota | |||
| spec: | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| io.kompose.service: db | |||
| strategy: | |||
| type: Recreate | |||
| template: | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: db | |||
| spec: | |||
| containers: | |||
| - env: | |||
| - name: POSTGRES_DB | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: POSTGRES_DB | |||
| name: env-prod-db | |||
| - name: POSTGRES_PASSWORD | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: POSTGRES_PASSWORD | |||
| name: env-prod-db | |||
| - name: POSTGRES_USER | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: POSTGRES_USER | |||
| name: env-prod-db | |||
| image: postgres:15 | |||
| name: db | |||
| volumeMounts: | |||
| - mountPath: /var/lib/postgresql/data | |||
| name: postgres-data | |||
| restartPolicy: Always | |||
| volumes: | |||
| - name: postgres-data | |||
| persistentVolumeClaim: | |||
| claimName: postgres-data | |||
| @ -0,0 +1,17 @@ | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: db | |||
| name: db | |||
| namespace: reymota | |||
| spec: | |||
| ports: | |||
| - name: "5432" | |||
| port: 5432 | |||
| targetPort: 5432 | |||
| selector: | |||
| io.kompose.service: db | |||
| @ -0,0 +1 @@ | |||
| kubectl -n reymota exec -ti deployment.apps/reymota -- /bin/bash | |||
| @ -0,0 +1 @@ | |||
| kubectl -n reymota exec -ti deployment.apps/db -- psql --username=creylopez --dbname=reymota | |||
| @ -0,0 +1,19 @@ | |||
| apiVersion: v1 | |||
| data: | |||
| DEBUG: "True" | |||
| DJANGO_ALLOWED_HOSTS: "reymota.es k8s-server localhost 127.0.0.1 [::1]" | |||
| CSRF_TRUSTED_ORIGINS: "https://reymota.es" | |||
| SECRET_KEY: change_me | |||
| SQL_DATABASE: reymota | |||
| SQL_ENGINE: django.db.backends.postgresql | |||
| SQL_HOST: db | |||
| SQL_PASSWORD: Dsa-0213 | |||
| SQL_PORT: "5432" | |||
| SQL_USER: creylopez | |||
| DATABASE: postgres | |||
| kind: ConfigMap | |||
| metadata: | |||
| labels: | |||
| io.kompose.service: web-env-prod | |||
| name: env-prod | |||
| namespace: reymota | |||
| @ -0,0 +1,11 @@ | |||
| apiVersion: v1 | |||
| data: | |||
| POSTGRES_DB: reymota | |||
| POSTGRES_PASSWORD: Dsa-0213 | |||
| POSTGRES_USER: creylopez | |||
| kind: ConfigMap | |||
| metadata: | |||
| labels: | |||
| io.kompose.service: db-env-prod-db | |||
| name: env-prod-db | |||
| namespace: reymota | |||
| @ -0,0 +1,7 @@ | |||
| ################################################### | |||
| # Namespace Vehículos | |||
| ################################################### | |||
| apiVersion: v1 | |||
| kind: Namespace | |||
| metadata: | |||
| name: reymota | |||
| @ -0,0 +1,46 @@ | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: nginx | |||
| name: nginx | |||
| namespace: reymota | |||
| spec: | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| io.kompose.service: nginx | |||
| strategy: | |||
| type: Recreate | |||
| template: | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: nginx | |||
| spec: | |||
| containers: | |||
| - image: $REGISTRY/nginx-reymota-$ARQUITECTURA:$IMG_NGINX_VERSION | |||
| name: nginx | |||
| ports: | |||
| - containerPort: 80 | |||
| protocol: TCP | |||
| volumeMounts: | |||
| - mountPath: /app/reymota/staticfiles | |||
| name: static-volume | |||
| - mountPath: /app/reymota/mediafiles | |||
| name: reymota-media | |||
| imagePullSecrets: | |||
| - name: myregistrykey | |||
| restartPolicy: Always | |||
| volumes: | |||
| - name: static-volume | |||
| persistentVolumeClaim: | |||
| claimName: static-volume | |||
| - name: reymota-media | |||
| persistentVolumeClaim: | |||
| claimName: reymota-media | |||
| @ -0,0 +1,20 @@ | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| annotations: | |||
| kompose.cmd: kompose convert | |||
| kompose.version: 1.34.0 (cbf2835db) | |||
| labels: | |||
| io.kompose.service: nginx | |||
| name: nginx | |||
| namespace: reymota | |||
| spec: | |||
| type: NodePort | |||
| ports: | |||
| - name: "1337" | |||
| port: 1337 | |||
| nodePort: 30341 | |||
| targetPort: 80 | |||
| selector: | |||
| io.kompose.service: nginx | |||
| @ -0,0 +1,13 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| labels: | |||
| io.kompose.service: postgres-data | |||
| name: postgres-data | |||
| namespace: reymota | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 100Mi | |||
| @ -0,0 +1,111 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: reymota-media-folder | |||
| namespace: reymota | |||
| labels: | |||
| app: reymota | |||
| spec: | |||
| capacity: | |||
| storage: 100Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| #path: "/mnt/Externo/reymota/media" | |||
| path: "/mnt/Externo/copiareymota/media" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: reymota-lyrics-migrations-folder | |||
| namespace: reymota | |||
| labels: | |||
| app: reymota | |||
| spec: | |||
| capacity: | |||
| storage: 50Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| #path: "/mnt/Externo/reymota/migrations/lyrics" | |||
| path: "/mnt/Externo/copiareymota/migrations/lyrics" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: reymota-libros-migrations-folder | |||
| namespace: reymota | |||
| labels: | |||
| app: reymota | |||
| spec: | |||
| capacity: | |||
| storage: 51Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| #path: "/mnt/Externo/reymota/migrations/libros" | |||
| path: "/mnt/Externo/copiareymota/migrations/libros" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: reymota-repostajes-migrations-folder | |||
| namespace: reymota | |||
| labels: | |||
| app: reymota | |||
| spec: | |||
| capacity: | |||
| storage: 52Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| #path: "/mnt/Externo/reymota/migrations/repostajes" | |||
| path: "/mnt/Externo/copiareymota/migrations/repostajes" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: reymota-reymotausers-migrations-folder | |||
| namespace: reymota | |||
| labels: | |||
| app: reymota | |||
| spec: | |||
| capacity: | |||
| storage: 53Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| #path: "/mnt/Externo/reymota/migrations/reymotausers" | |||
| path: "/mnt/Externo/copiareymota/migrations/reymotausers" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: reymota-static-folder | |||
| namespace: reymota | |||
| labels: | |||
| app: reymota | |||
| spec: | |||
| capacity: | |||
| storage: 70Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| #path: "/mnt/Externo/reymota/static" | |||
| path: "/mnt/Externo/copiareymota/static" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: reymota-pg-folder | |||
| namespace: reymota | |||
| labels: | |||
| app: reymota | |||
| spec: | |||
| capacity: | |||
| storage: 200Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| #path: "/mnt/Externo/reymota/pg" | |||
| path: "/mnt/Externo/copiareymota/pg" | |||
| @ -0,0 +1,8 @@ | |||
| apiVersion: v1 | |||
| kind: Secret | |||
| metadata: | |||
| name: myregistrykey | |||
| namespace: reymota | |||
| data: | |||
| .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJyZWdpc3RyeS5yZXltb3RhLmVzIjogewoJCQkiYXV0aCI6ICJZM0psZVd4dmNHVjZPbEpsZVMweE1UYzIiCgkJfQoJfQp9 | |||
| type: kubernetes.io/dockerconfigjson | |||
| @ -0,0 +1,141 @@ | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| name: reymota | |||
| namespace: reymota | |||
| spec: | |||
| ports: | |||
| - name: "8000" | |||
| port: 8000 | |||
| targetPort: 8000 | |||
| selector: | |||
| app: reymota | |||
| --- | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| name: reymota | |||
| namespace: reymota | |||
| labels: | |||
| app: reymota | |||
| spec: | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| app: reymota | |||
| strategy: | |||
| type: Recreate | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: reymota | |||
| spec: | |||
| containers: | |||
| - args: | |||
| - gunicorn | |||
| - reymota.wsgi:application | |||
| - --bind | |||
| - 0.0.0.0:8000 | |||
| name: reymota | |||
| image: $REGISTRY/reymota-$ARQUITECTURA:$IMG_VERSION | |||
| env: | |||
| - name: VERSION | |||
| value: "$IMG_VERSION" | |||
| - name: ENVIRONMENT | |||
| value: "Producción" | |||
| - name: DEBUG | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: DEBUG | |||
| name: env-prod | |||
| - name: DJANGO_ALLOWED_HOSTS | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: DJANGO_ALLOWED_HOSTS | |||
| name: env-prod | |||
| - name: CSRF_TRUSTED_ORIGINS | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: CSRF_TRUSTED_ORIGINS | |||
| name: env-prod | |||
| - name: SECRET_KEY | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SECRET_KEY | |||
| name: env-prod | |||
| - name: DATABASE | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: DATABASE | |||
| name: env-prod | |||
| - name: SQL_HOST | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_HOST | |||
| name: env-prod | |||
| - name: SQL_PORT | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_PORT | |||
| name: env-prod | |||
| - name: SQL_ENGINE | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_ENGINE | |||
| name: env-prod | |||
| - name: SQL_DATABASE | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_DATABASE | |||
| name: env-prod | |||
| - name: SQL_USER | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_USER | |||
| name: env-prod | |||
| - name: SQL_PASSWORD | |||
| valueFrom: | |||
| configMapKeyRef: | |||
| key: SQL_PASSWORD | |||
| name: env-prod | |||
| ports: | |||
| - containerPort: 8000 | |||
| protocol: TCP | |||
| volumeMounts: | |||
| - mountPath: /app/reymota/mediafiles | |||
| name: reymota-media | |||
| - mountPath: /app/reymota/lyrics/migrations | |||
| name: reymota-lyrics-migrations | |||
| - mountPath: /app/reymota/repostajes/migrations | |||
| name: reymota-repostajes-migrations | |||
| - mountPath: /app/reymota/libros/migrations | |||
| name: reymota-libros-migrations | |||
| - mountPath: /app/reymota/reymotausers/migrations | |||
| name: reymota-reymotausers-migrations | |||
| - mountPath: /app/reymota/staticfiles | |||
| name: static-volume | |||
| imagePullSecrets: | |||
| - name: myregistrykey | |||
| restartPolicy: Always | |||
| volumes: | |||
| - name: reymota-media | |||
| persistentVolumeClaim: | |||
| claimName: reymota-media | |||
| - name: reymota-lyrics-migrations | |||
| persistentVolumeClaim: | |||
| claimName: reymota-lyrics-migrations | |||
| - name: reymota-repostajes-migrations | |||
| persistentVolumeClaim: | |||
| claimName: reymota-repostajes-migrations | |||
| - name: reymota-libros-migrations | |||
| persistentVolumeClaim: | |||
| claimName: reymota-libros-migrations | |||
| - name: reymota-reymotausers-migrations | |||
| persistentVolumeClaim: | |||
| claimName: reymota-reymotausers-migrations | |||
| - name: static-volume | |||
| persistentVolumeClaim: | |||
| claimName: static-volume | |||
| status: {} | |||
| @ -0,0 +1,79 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| creationTimestamp: null | |||
| labels: | |||
| io.kompose.service: reymota-media | |||
| name: reymota-media | |||
| namespace: reymota | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 100Mi | |||
| status: {} | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| creationTimestamp: null | |||
| labels: | |||
| io.kompose.service: reymota-libros-migrations | |||
| name: reymota-libros-migrations | |||
| namespace: reymota | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 51Mi | |||
| status: {} | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| creationTimestamp: null | |||
| labels: | |||
| io.kompose.service: reymota-lyrics-migrations | |||
| name: reymota-lyrics-migrations | |||
| namespace: reymota | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 50Mi | |||
| status: {} | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| creationTimestamp: null | |||
| labels: | |||
| io.kompose.service: reymota-repostajes-migrations | |||
| name: reymota-repostajes-migrations | |||
| namespace: reymota | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 52Mi | |||
| status: {} | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| creationTimestamp: null | |||
| labels: | |||
| io.kompose.service: reymota-reymotausers-migrations | |||
| name: reymota-reymotausers-migrations | |||
| namespace: reymota | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 53Mi | |||
| status: {} | |||
| @ -0,0 +1,13 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| labels: | |||
| io.kompose.service: static-volume | |||
| name: static-volume | |||
| namespace: reymota | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 70Mi | |||
| @ -0,0 +1,140 @@ | |||
| -- | |||
| -- PostgreSQL database dump | |||
| -- | |||
| -- Dumped from database version 15.8 (Debian 15.8-1.pgdg120+1) | |||
| -- Dumped by pg_dump version 15.8 (Debian 15.8-1.pgdg120+1) | |||
| SET statement_timeout = 0; | |||
| SET lock_timeout = 0; | |||
| SET idle_in_transaction_session_timeout = 0; | |||
| SET client_encoding = 'UTF8'; | |||
| SET standard_conforming_strings = on; | |||
| SELECT pg_catalog.set_config('search_path', '', false); | |||
| SET check_function_bodies = false; | |||
| SET xmloption = content; | |||
| SET client_min_messages = warning; | |||
| SET row_security = off; | |||
| SET default_tablespace = ''; | |||
| SET default_table_access_method = heap; | |||
| -- | |||
| -- Data for Name: repostajes_vehiculo; Type: TABLE DATA; Schema: public; Owner: creylopez | |||
| -- | |||
| COPY public.repostajes_vehiculo (id, marca, modelo, matricula, foto) FROM stdin; | |||
| 5 BMW 318d 1018KPD vehiculos/bmws3.png | |||
| 4 Toyota Corolla 7630LYR vehiculos/corolla.png | |||
| \. | |||
| -- | |||
| -- Name: repostajes_repostaje; Type: TABLE; Schema: public; Owner: creylopez | |||
| -- | |||
| -- | |||
| -- Data for Name: repostajes_repostaje; Type: TABLE DATA; Schema: public; Owner: creylopez | |||
| -- | |||
| COPY public.repostajes_repostaje (id, fecha, kms, litros, descuento, importe, precioxlitro, kmsrecorridos, consumo, vehiculo_id) FROM stdin; | |||
| 16 2021-12-14 52731 0.00 0.00 0.00 0.00 52731 0.00 5 | |||
| 17 2021-12-23 53162 52.80 0.00 67.32 1.28 431 12.25 5 | |||
| 18 2021-12-31 54122 49.99 0.00 63.74 1.28 960 5.21 5 | |||
| 19 2022-01-22 54946 49.14 0.00 62.65 1.27 824 5.96 5 | |||
| 20 2022-02-09 55908 49.24 0.00 65.24 1.32 962 5.12 5 | |||
| 21 2022-03-03 56909 48.61 0.00 67.03 1.38 1001 4.86 5 | |||
| 22 2022-03-18 57542 30.06 0.00 52.54 1.75 633 4.75 5 | |||
| 23 2022-04-10 58497 46.63 0.00 69.98 1.50 955 4.88 5 | |||
| 24 2022-05-12 59447 47.14 0.00 72.11 1.53 950 4.96 5 | |||
| 25 2022-05-19 60414 48.57 0.00 79.81 1.64 967 5.02 5 | |||
| 26 2022-06-09 61147 36.20 0.00 62.12 1.72 733 4.94 5 | |||
| 27 2022-06-25 62116 49.17 0.00 90.29 1.84 969 5.07 5 | |||
| 28 2022-09-14 66359 53.24 0.00 84.83 1.59 1174 4.53 5 | |||
| 29 2022-09-23 67107 37.26 0.00 55.48 1.49 748 4.98 5 | |||
| 30 2023-01-24 71790 43.04 2.12 70.54 1.59 871 4.94 5 | |||
| 31 2022-12-03 70061 46.38 2.04 68.13 1.42 903 5.14 5 | |||
| 32 2022-12-26 70919 44.58 1.85 61.68 1.34 858 5.20 5 | |||
| 33 2023-03-05 73711 47.85 0.00 71.20 1.49 948 5.05 5 | |||
| 34 2023-03-25 74749 49.84 0.00 72.17 1.45 1038 4.80 5 | |||
| 35 2023-02-19 72763 49.38 2.34 77.97 1.53 973 5.08 5 | |||
| 36 2023-05-06 76434 32.28 0.00 44.09 1.37 1685 1.92 5 | |||
| 37 2023-05-22 77366 45.04 0.00 58.46 1.30 932 4.83 5 | |||
| 38 2022-07-09 63129 47.03 0.00 79.38 1.69 1013 4.64 5 | |||
| 39 2022-08-12 64088 43.73 0.00 65.55 1.50 959 4.56 5 | |||
| 40 2022-08-22 65185 52.78 0.00 78.80 1.49 1097 4.81 5 | |||
| 41 2022-10-12 68204 52.04 2.51 83.73 1.56 1097 4.74 5 | |||
| 42 2022-11-11 69158 45.28 2.37 78.91 1.69 954 4.75 5 | |||
| 43 2023-06-10 78170 41.09 0.00 54.16 1.32 804 5.11 5 | |||
| 44 2023-06-19 79038 40.78 1.95 60.11 1.43 868 4.70 5 | |||
| 45 2022-06-28 219 9.88 0.00 18.96 1.92 219 4.51 4 | |||
| 46 2022-06-28 236 27.36 0.00 51.33 1.88 17 160.94 4 | |||
| 47 2022-07-14 904 32.24 0.00 55.58 1.72 668 4.83 4 | |||
| 48 2022-07-26 1433 30.49 0.00 48.43 1.59 529 5.76 4 | |||
| 49 2022-08-21 2030 32.92 0.00 46.72 1.42 597 5.51 4 | |||
| 50 2022-09-26 2627 23.92 0.00 33.16 1.39 597 4.01 4 | |||
| 51 2022-10-18 3169 22.97 0.00 32.74 1.43 542 4.24 4 | |||
| 52 2022-11-09 3791 29.60 0.00 41.88 1.41 622 4.76 4 | |||
| 53 2022-11-27 4363 28.80 1.20 38.80 1.35 572 5.03 4 | |||
| 54 2022-12-22 4851 26.74 1.06 34.18 1.28 488 5.48 4 | |||
| 55 2023-01-12 5291 23.52 1.09 35.34 1.50 440 5.35 4 | |||
| 56 2023-02-01 5702 27.36 1.28 41.52 1.52 411 6.66 4 | |||
| 57 2023-02-20 6141 24.09 1.13 36.67 1.52 439 5.49 4 | |||
| 58 2023-03-15 6631 25.52 1.21 38.96 1.53 490 5.21 4 | |||
| 59 2023-04-17 7325 29.40 1.47 47.62 1.62 694 4.24 4 | |||
| 60 2023-05-28 8413 24.16 1.17 37.70 1.56 1088 2.22 4 | |||
| 61 2023-06-25 8956 26.38 1.30 41.94 1.59 543 4.86 4 | |||
| 62 2023-07-10 9471 29.04 1.35 43.49 1.50 515 5.64 4 | |||
| 63 2023-07-14 79875 40.56 1.74 56.26 1.41 837 4.85 5 | |||
| 64 2023-07-22 80806 46.29 1.95 63.05 1.37 931 4.97 5 | |||
| 65 2023-07-25 10043 24.85 1.40 40.32 1.62 572 4.34 4 | |||
| 66 2023-08-07 81695 44.39 0.00 63.88 1.44 889 4.99 5 | |||
| 67 2023-08-09 10582 26.49 1.39 44.94 1.70 539 4.91 4 | |||
| 68 2023-08-23 11050 24.05 1.22 39.40 1.64 468 5.14 4 | |||
| 69 2023-08-27 82715 50.40 0.00 77.06 1.53 1020 4.94 5 | |||
| 70 2023-09-14 11508 21.44 1.14 37.00 1.73 458 4.68 4 | |||
| 71 2023-09-19 83709 48.35 0.00 77.26 1.60 994 4.86 5 | |||
| 72 2023-09-27 84171 23.01 0.00 35.85 1.56 462 4.98 5 | |||
| 73 2023-10-10 85104 48.00 0.00 72.43 1.51 933 5.14 5 | |||
| 74 2023-10-15 12006 25.09 1.25 40.37 1.61 498 5.04 4 | |||
| 75 2023-10-27 86021 46.77 0.00 70.11 1.50 917 5.10 5 | |||
| 76 2023-11-04 12427 25.64 1.17 37.78 1.47 421 6.09 4 | |||
| 77 2023-11-11 86757 39.58 1.71 55.33 1.40 736 5.38 5 | |||
| 78 2023-11-20 12933 26.16 0.00 40.00 1.53 506 5.17 4 | |||
| 79 2023-11-23 87503 42.41 1.75 56.45 1.33 746 5.68 5 | |||
| 80 2023-12-04 88256 41.19 0.00 57.62 1.40 753 5.47 5 | |||
| 81 2023-12-17 88964 41.20 1.66 53.78 1.31 708 5.82 5 | |||
| 82 2024-01-06 13414 30.72 1.34 43.36 1.41 481 6.39 4 | |||
| 83 2024-01-07 89802 47.77 1.91 61.75 1.29 838 5.70 5 | |||
| 84 2024-01-22 13903 25.08 0.00 37.09 1.48 489 5.13 4 | |||
| 85 2024-01-27 90723 45.25 0.00 60.37 1.33 921 4.91 5 | |||
| 86 2024-02-11 14365 28.45 0.00 41.37 1.45 462 6.16 4 | |||
| 87 2024-02-12 91672 48.31 0.00 70.00 1.45 949 5.09 5 | |||
| 88 2024-02-27 92489 41.99 0.00 57.91 1.38 817 5.14 5 | |||
| 89 2024-02-29 14857 23.96 1.12 36.35 1.52 492 4.87 4 | |||
| 90 2024-03-18 15287 13.00 0.00 20.00 1.54 430 3.02 4 | |||
| 91 2024-03-19 93327 43.85 0.00 60.25 1.37 838 5.23 5 | |||
| 92 2024-03-25 15537 19.24 0.00 30.00 1.56 250 7.70 4 | |||
| 93 2024-04-06 15935 29.39 0.00 43.47 1.48 398 7.38 4 | |||
| 94 2024-04-08 94167 41.11 0.00 56.49 1.37 840 4.89 5 | |||
| 95 2024-04-22 16465 25.92 0.00 40.66 1.57 530 4.89 4 | |||
| 96 2024-04-29 95042 43.63 0.00 63.03 1.45 875 4.99 5 | |||
| 97 2024-05-13 16963 26.80 0.00 41.51 1.55 498 5.38 4 | |||
| 98 2024-05-21 96585 28.33 0.00 39.63 1.40 572 4.95 5 | |||
| 99 2024-05-27 97597 49.48 0.00 67.96 1.37 1012 4.89 5 | |||
| 100 2024-05-06 96013 50.59 0.00 73.32 1.45 971 5.21 5 | |||
| 101 2024-06-03 98067 23.97 0.00 32.69 1.36 470 5.10 5 | |||
| 102 2024-06-08 98609 28.28 1.25 40.44 1.43 542 5.22 5 | |||
| 103 2024-06-10 17494 26.72 0.00 39.92 1.49 531 5.03 4 | |||
| 104 2024-06-17 99166 26.91 0.00 36.43 1.35 557 4.83 5 | |||
| 105 2024-06-26 17879 18.91 0.00 28.44 1.50 385 4.91 4 | |||
| 106 2024-06-30 100048 44.39 0.00 61.57 1.39 882 5.03 5 | |||
| 107 2024-07-10 18397 25.42 0.00 38.49 1.51 518 4.91 4 | |||
| 108 2024-07-21 18944 27.71 0.00 40.29 1.45 547 5.07 4 | |||
| 109 2024-07-23 101010 45.25 0.00 60.52 1.34 962 4.70 5 | |||
| 110 2024-08-09 19596 32.19 0.00 43.58 1.35 652 4.94 4 | |||
| 111 2024-08-12 101710 30.69 0.00 39.10 1.27 700 4.38 5 | |||
| 112 2024-08-25 20185 29.08 0.00 38.07 1.31 589 4.94 4 | |||
| 1 2024-08-31 102649 45.27 0.00 55.64 1.23 939 4.82 5 | |||
| 2 2024-09-15 20775 29.51 0.00 39.51 1.34 590 5.00 4 | |||
| \. | |||
| @ -0,0 +1 @@ | |||
| docker run -it registry.reymota.es/reymota-x86_64:0.1 bash | |||
| @ -0,0 +1,8 @@ | |||
| install: | |||
| echo "Creando imagen con version '${IMG_VERSION}' para la arquitectura '${ARQUITECTURA}' en el registry '${REGISTRY}'" | |||
| docker build --no-cache -t ${REGISTRY}/reymota-${ARQUITECTURA}:${IMG_VERSION} . | |||
| docker push ${REGISTRY}/reymota-${ARQUITECTURA}:${IMG_VERSION} | |||
| @ -0,0 +1,49 @@ | |||
| # Instalación | |||
| Desde el directorio K8S ejecutar make (esto hace todo: la imagen, para los pods y los lanza otra vez) | |||
| La primera vez, hay que entrar en el pod de vehículos con 'entra.sh' y | |||
| python manage.py createsuperuser | |||
| python manage.py makemigrations | |||
| python manage.py migrate | |||
| ## Comprobar la base de datos | |||
| Con la shell entraPsql.sh: | |||
| \l para listar las BD | |||
| \c reymota para usar nuestra db | |||
| \dt para ver las tablas | |||
| # De dónde cogí ideas | |||
| https://learndjango.com/tutorials/django-login-and-logout-tutorial | |||
| Username: {{ user.username }} | |||
| User Full name: {{ user.get_full_name }} | |||
| User Group: {{ user.groups.all.0 }} | |||
| Email: {{ user.email }} | |||
| Session Started at: {{ user.last_login }} | |||
| ## Para funcionar con gunicorn y nginx | |||
| https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/ | |||
| ## Cambiar la secuencia de lo sid | |||
| ALTER SEQUENCE tablename_id_seq RESTART WITH nn; | |||
| esto se hace cuando restauro un volcado de la bd sobre una instalación nueva. Si hay índices ya creados, hay que reinciar a partir del último. | |||
| @ -0,0 +1,20 @@ | |||
| #!/bin/bash | |||
| if [ "$DATABASE" = "postgres" ] | |||
| then | |||
| echo "Waiting for postgres..." | |||
| while ! nc -z $SQL_HOST $SQL_PORT; do | |||
| sleep 0.1 | |||
| done | |||
| echo "PostgreSQL started" | |||
| else | |||
| echo "la base de datos no es postgres: '$DATABASE'" | |||
| fi | |||
| python manage.py collectstatic --noinput | |||
| #python manage.py flush --no-input | |||
| #python manage.py migrate | |||
| exec "$@" | |||
| @ -0,0 +1 @@ | |||
| migrations/ | |||
| @ -0,0 +1,3 @@ | |||
| from django.contrib import admin | |||
| # Register your models here. | |||
| @ -0,0 +1,6 @@ | |||
| from django.apps import AppConfig | |||
| class AccountsConfig(AppConfig): | |||
| default_auto_field = 'django.db.models.BigAutoField' | |||
| name = 'accounts' | |||
| @ -0,0 +1,3 @@ | |||
| from django.db import models | |||
| # Create your models here. | |||
| @ -0,0 +1,3 @@ | |||
| from django.test import TestCase | |||
| # Create your tests here. | |||
| @ -0,0 +1,8 @@ | |||
| # accounts/urls.py | |||
| from django.urls import path | |||
| from django.contrib.auth import views as auth_views | |||
| urlpatterns = [ | |||
| path('login/', auth_views.LoginView.as_view(), name='login'), | |||
| path('logout/', auth_views.LogoutView.as_view(), name='logout'), | |||
| ] | |||
| @ -0,0 +1 @@ | |||
| from django.shortcuts import render | |||
| @ -0,0 +1,6 @@ | |||
| export CSRF_TRUSTED_ORIGINS="http://localhost" | |||
| export DEBUG="True" | |||
| export SECRET_KEY="hola" | |||
| export DJANGO_ALLOWED_HOSTS="localhost" | |||
| @ -0,0 +1,23 @@ | |||
| # Generated by Django 4.2 on 2024-09-30 14:19 | |||
| from django.conf import settings | |||
| from django.db import migrations, models | |||
| import django.db.models.deletion | |||
| class Migration(migrations.Migration): | |||
| initial = True | |||
| dependencies = [ | |||
| ('eventos', '0001_initial'), | |||
| migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |||
| ] | |||
| operations = [ | |||
| migrations.AddField( | |||
| model_name='reserva', | |||
| name='usuario', | |||
| field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), | |||
| ), | |||
| ] | |||
| @ -0,0 +1,9 @@ | |||
| import os | |||
| from django import template | |||
| register = template.Library() | |||
| @register.filter | |||
| def muestra_version(clave): | |||
| return os.getenv(clave, '') | |||
| @ -0,0 +1,43 @@ | |||
| from django.contrib import admin | |||
| from django.contrib.auth.admin import UserAdmin | |||
| # Register your models here. | |||
| from reymotausers.models import ReyMotaUser | |||
| from reymotausers.forms import ReyMotaUserCreationForm, ReyMotaUserChangeForm | |||
| class ReyMotaUserAdmin(UserAdmin): | |||
| add_form = ReyMotaUserCreationForm | |||
| form = ReyMotaUserChangeForm | |||
| model = ReyMotaUser | |||
| list_display = ("email", "nombre", "is_staff", "is_active", "foto") | |||
| list_filter = ("email", "nombre", "is_staff", "is_active",) | |||
| fieldsets = ( | |||
| (None, {"fields": ("email", "password")}), | |||
| ("Personal", {"fields": ("nombre",)}), | |||
| ("Permissions", {"fields": ("is_staff", "is_active", "groups", | |||
| "user_permissions")}), | |||
| ("Varios", {"fields": ("foto",)}), | |||
| ) | |||
| add_fieldsets = ( | |||
| ( | |||
| None, | |||
| { | |||
| "classes": ("wide",), | |||
| "fields": ( | |||
| "email", "password1", "password2", "is_staff", | |||
| "is_active", "groups", "user_permissions" | |||
| ) | |||
| } | |||
| ), | |||
| ("Personal", {"fields": ("nombre",)}), | |||
| ("Varios", {"fields": ("foto",)}), | |||
| ) | |||
| search_fields = ("email",) | |||
| ordering = ("email",) | |||
| admin.site.register(ReyMotaUser, ReyMotaUserAdmin) | |||
| @ -0,0 +1,6 @@ | |||
| from django.apps import AppConfig | |||
| class ReymotausersConfig(AppConfig): | |||
| default_auto_field = 'django.db.models.BigAutoField' | |||
| name = 'reymotausers' | |||
| @ -0,0 +1,19 @@ | |||
| from django import forms | |||
| from django.contrib.auth.forms import UserCreationForm, UserChangeForm | |||
| from .models import ReyMotaUser | |||
| 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") | |||
| @ -0,0 +1,34 @@ | |||
| from django.contrib.auth.base_user import BaseUserManager | |||
| from django.utils.translation import gettext_lazy as _ | |||
| class ReyMotaUserManager(BaseUserManager): | |||
| """ | |||
| ReyMota user model manager where email is the unique identifiers | |||
| for authentication instead of usernames. | |||
| """ | |||
| def create_user(self, email, password, **extra_fields): | |||
| """ | |||
| Create and save a user with the given email and password. | |||
| """ | |||
| if not email: | |||
| raise ValueError(_("The Email must be set")) | |||
| email = self.normalize_email(email) | |||
| user = self.model(email=email, **extra_fields) | |||
| user.set_password(password) | |||
| user.save() | |||
| return user | |||
| def create_superuser(self, email, password, **extra_fields): | |||
| """ | |||
| Create and save a SuperUser with the given email and password. | |||
| """ | |||
| extra_fields.setdefault("is_staff", True) | |||
| extra_fields.setdefault("is_superuser", True) | |||
| extra_fields.setdefault("is_active", True) | |||
| if extra_fields.get("is_staff") is not True: | |||
| raise ValueError(_("Superuser must have is_staff=True.")) | |||
| if extra_fields.get("is_superuser") is not True: | |||
| raise ValueError(_("Superuser must have is_superuser=True.")) | |||
| return self.create_user(email, password, **extra_fields) | |||
| @ -0,0 +1,34 @@ | |||
| # Generated by Django 4.2 on 2024-09-30 14:19 | |||
| from django.db import migrations, models | |||
| class Migration(migrations.Migration): | |||
| initial = True | |||
| dependencies = [ | |||
| ('auth', '0012_alter_user_first_name_max_length'), | |||
| ] | |||
| operations = [ | |||
| migrations.CreateModel( | |||
| name='ReyMotaUser', | |||
| fields=[ | |||
| ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||
| ('password', models.CharField(max_length=128, verbose_name='password')), | |||
| ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), | |||
| ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), | |||
| ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')), | |||
| ('foto', models.ImageField(blank=True, default='profile_images/default.jpg', upload_to='profile_images')), | |||
| ('is_staff', models.BooleanField(default=False)), | |||
| ('is_active', models.BooleanField(default=True)), | |||
| ('nombre', models.CharField(blank=True, max_length=200, null=True)), | |||
| ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), | |||
| ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), | |||
| ], | |||
| options={ | |||
| 'abstract': False, | |||
| }, | |||
| ), | |||
| ] | |||
| @ -0,0 +1,24 @@ | |||
| from django.db import models | |||
| # Create your models here. | |||
| from django.utils.translation import gettext_lazy as _ | |||
| from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin | |||
| from .managers import ReyMotaUserManager | |||
| # Create your models here. | |||
| class ReyMotaUser(AbstractBaseUser, PermissionsMixin): | |||
| email = models.EmailField(_("email address"), unique=True) | |||
| foto = models.ImageField(upload_to="profile_images", default="profile_images/default.jpg", blank=True) | |||
| is_staff = models.BooleanField(default=False) | |||
| is_active = models.BooleanField(default=True) | |||
| nombre = models.CharField(max_length=200, blank=True, null=True) | |||
| USERNAME_FIELD = "email" | |||
| REQUIRED_FIELDS = [] | |||
| objects = ReyMotaUserManager() | |||
| def __str__(self): | |||
| return self.email | |||
| @ -0,0 +1,3 @@ | |||
| from django.test import TestCase | |||
| # Create your tests here. | |||
| @ -0,0 +1,3 @@ | |||
| from django.shortcuts import render | |||
| # Create your views here. | |||
| @ -0,0 +1,14 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| <div class="app-card p-5 text-center shadow-sm"> | |||
| <h1 class="page-title mb-4">404<br><span class="font-weight-light">Página no encontrada</span></h1> | |||
| <div class="mb-4"> | |||
| Lo siento, no hemos podido encontrar la página que buscas. | |||
| </div> | |||
| <a class="btn app-btn-primary" href="{{ url_for('paginas.index') }}">Ir a la página de inicio</a> | |||
| </div> | |||
| {% endblock %} | |||
| @ -0,0 +1,8 @@ | |||
| {% load static %} | |||
| {% load filtros_de_entorno %} | |||
| <div class="app-branding"> | |||
| <a class="app-logo" href="{% url 'principal' %}"><img class="logo-icon me-2" src="{% static 'images/reymota-logo.svg' %}" alt="logo"><span class="logo-text">REYMOTA</span><span style="color: blue; font-size: 14px;"> v {{ "VERSION"|muestra_version }}</span></a> | |||
| </div><!--//app-branding--> | |||
| @ -0,0 +1,123 @@ | |||
| {% 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--> | |||
| {% block menuapp %} | |||
| <div class="search-mobile-trigger d-sm-none col"> | |||
| <i class="search-mobile-trigger-icon fa-solid fa-magnifying-glass"></i> | |||
| </div><!--//col--> | |||
| <div class="app-search-box col"> | |||
| <form class="app-search-form"> | |||
| <input type="text" placeholder="Busca..." name="search" class="form-control search-input"> | |||
| <button type="submit" class="btn search-btn btn-primary" value="Search"><i class="fa-solid fa-magnifying-glass"></i></button> | |||
| </form> | |||
| </div><!--//app-search-box--> | |||
| {% endblock menuapp %} | |||
| <div class="app-utilities col-auto"> | |||
| <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' %}">Vehículos</a></li> | |||
| <li class="submenu-item"><a class="submenu-link" href="{% url 'lyrics:principal' %}">Letras</a></li> | |||
| </ul> | |||
| </div> | |||
| </li><!--//nav-item--> | |||
| {% endif %} | |||
| </ul><!--//app-menu--> | |||
| </nav><!--//app-nav--> | |||
| </div><!--//sidepanel-inner--> | |||
| </div><!--//app-sidepanel--> | |||
| </header><!--//app-header--> | |||
| @ -0,0 +1,10 @@ | |||
| <!-- | |||
| La clase app-auth-footer hace algo que implica que el texto quede | |||
| en la parte de abajo de la ventana con el tamaño que esta tenga en el momento | |||
| de renderizar el texto. En algunos casos esto causa un efecto no deseado. Por ejemplo en letras.html | |||
| --> | |||
| <!--<footer class="app-auth-footer">--> | |||
| <div class="container text-center py-3"> | |||
| <small class="copyright">(c) <a class="app-link" href="http://reymota.es" target="_blank">Celestino Rey</a></small> | |||
| </div> | |||
| <!--</footer>//app-auth-footer--> | |||
| @ -0,0 +1,23 @@ | |||
| {% 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> | |||
| @ -0,0 +1,176 @@ | |||
| {% load static %} | |||
| {% include "_head.html" %} | |||
| <body class="app"> | |||
| <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"> | |||
| {% block menuapp %} | |||
| <div class="app-utility-item app-user-dropdown dropdown"> | |||
| </div> | |||
| {% endblock menuapp %} | |||
| <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 propias</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' %}">Vehículos</a></li> | |||
| <li class="submenu-item"><a class="submenu-link" href="{% url 'lyrics:principal' %}">Letras</a></li> | |||
| </ul> | |||
| </div> | |||
| </li><!--//nav-item--> | |||
| <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 externas</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="https://navidrome.reymota.es" target="_blank">Navidrome</a></li> | |||
| <li class="submenu-item"><a class="submenu-link" href="https://firefly.reymota.es" target="_blank">Gestion economica</a></li> | |||
| <li class="submenu-item"><a class="submenu-link" href="https://gogs.reymota.es" target="_blank">Control de versiones</a></li> | |||
| <li class="submenu-item"><a class="submenu-link" href="https://wordpress.reymota.es" target="_blank">Blog</a></li> | |||
| </ul> | |||
| </div> | |||
| </li><!--//nav-item--> | |||
| {% endif %} | |||
| </ul><!--//app-menu--> | |||
| </nav><!--//app-nav--> | |||
| </div><!--//sidepanel-inner--> | |||
| </div><!--//app-sidepanel--> | |||
| </header><!--//app-header--> | |||
| <div class="app-wrapper"> | |||
| <div class="app-content pt-3 p-md-3 p-lg-4"> | |||
| {% block content %}{% endblock %} | |||
| </div><!--//app-content--> | |||
| {% include "_footer.html" %} | |||
| </div><!--//app-wrapper--> | |||
| <!-- Javascript --> | |||
| <script src="{% static 'plugins/popper.min.js' %}"></script> | |||
| <script src="{% static 'plugins/bootstrap/js/bootstrap.min.js' %}"></script> | |||
| <!-- Charts JS --> | |||
| <script src="{% static 'plugins/chart.js/chart.min.js' %}"></script> | |||
| <script src="{% static 'js/index-charts.js' %}"></script> | |||
| <!-- La línea siguiente es para la demo de los charts en charts.html --> | |||
| <script src="{% static 'js/charts-demo.js' %}"></script> | |||
| <!-- Page Specific JS --> | |||
| <script src="{% static 'js/app.js' %}"></script> | |||
| </body> | |||
| </html> | |||
| @ -0,0 +1,5 @@ | |||
| {% if user.is_authenticated %} | |||
| <a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><img src="{{ url_for('paginas.uploaded_file', filename=current_user.photo) }}" alt="user profile"></a> | |||
| {% else %} | |||
| <a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><img src="{{ url_for('static', filename='images/reymota-logo.svg') }}" alt="user profile"></a> | |||
| {% endif %} | |||
| @ -0,0 +1,27 @@ | |||
| {% 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 sitio REYMOTA.ES!</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><!--//container-fluid--> | |||
| {% endblock %} | |||
| @ -0,0 +1,21 @@ | |||
| <div class="app-utility-item app-user-dropdown dropdown"> | |||
| <a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Autores</a> | |||
| <ul class="dropdown-menu" aria-labelledby="user-dropdown-toggle"> | |||
| <li> | |||
| <a class="dropdown-item" href="{% url 'libros:lista_autores' %}">Ver</a> | |||
| </li> | |||
| </ul> | |||
| </div><!--//app-utility-item--> | |||
| <div class="app-utility-item app-user-dropdown dropdown"> | |||
| <a class="dropdown-toggle" id="user-dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">Libros</a> | |||
| <ul class="dropdown-menu" aria-labelledby="user-dropdown-toggle"> | |||
| <li> | |||
| <a class="dropdown-item" href="{% url 'libros:lista_libros' %}">Ver</a> | |||
| </li> | |||
| </ul> | |||
| </div><!--//app-utility-item--> | |||
| @ -0,0 +1,73 @@ | |||
| {% extends 'base.html' %} | |||
| {% block menuapp %} | |||
| {% include 'libros/_menu-libros.html' %} | |||
| {% endblock menuapp %} | |||
| {% block content %} | |||
| <div class="container-xl"> | |||
| <div class="app-card app-card-notification shadow-sm mb-4"> | |||
| <div class="app-card-header px-4 py-3"> | |||
| <div class="row g-3 align-items-center"> | |||
| <div class="col-12 col-lg-auto text-center text-lg-start"> | |||
| {% if autor.foto %} | |||
| <p><img src="{{ autor.foto.url }}" alt="{{ autor.nombre}}" style="width:200px;height:200px;"></p> | |||
| {% else %} | |||
| <p>No hay imágen disponible</p> | |||
| {% endif %} | |||
| </div> | |||
| <div class="col-12 col-lg-auto text-center text-lg-start"> | |||
| <h4>{{ autor.nombre }}</h4> | |||
| <ul class="notification-meta list-inline mb-0"> | |||
| <li class="list-inline-item">{{ autor.nombre }}</li> | |||
| </ul> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="app-card-body p-4"> | |||
| {% if libros %} | |||
| <table class="table app-table-hover mb-0 text-left"> | |||
| <thead> | |||
| <tr> | |||
| <th class="cell">Título</th> | |||
| <th class="cell">Portada</th> | |||
| </tr> | |||
| </thead> | |||
| <tbody> | |||
| {% for libro in libros %} | |||
| <tr> | |||
| <td class="cell"><a href="{% url 'libros:detalle_libro' libro.id %}">{{ libro.titulo }}</a></td> | |||
| {% if libro.portada %} | |||
| <td class="cell"><img src="{{ libro.portada.url }}" alt="Portada del libro" width="200"></td> | |||
| {% else %} | |||
| <td>Sin imagen</td> | |||
| {% endif %} | |||
| </tr> | |||
| {% endfor %} | |||
| </tbody> | |||
| </table> | |||
| {% else %} | |||
| <p>No se han encontrado libros para este autor</p> | |||
| {% endif %} | |||
| </div> | |||
| </div> | |||
| <div class="row g-3 mb-4 align-items-center justify-content-between"> | |||
| <div class="col-auto"> | |||
| <a class="btn app-btn-secondary" href="{% url 'libros:lista_libros' %}">Volver al inicio</a> | |||
| </div> | |||
| <div class="col-auto"> | |||
| <a class="btn app-btn-primary" href="{% url 'libros:nuevo_libro' %}">Añadir libro</a> <!-- Faltaría poner el id del autor--> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {% endblock %} | |||
| @ -0,0 +1,39 @@ | |||
| {% extends 'base.html' %} | |||
| {% block menuapp %} | |||
| {% include 'libros/_menu-libros.html' %} | |||
| {% endblock menuapp %} | |||
| {% block content %} | |||
| <div class="container-xl"> | |||
| <div class="app-card app-card-notification shadow-sm mb-4"> | |||
| <div class="app-card-header px-4 py-3"> | |||
| <div class="row g-3 align-items-center"> | |||
| <div class="col-12 col-lg-auto text-center text-lg-start"> | |||
| {% if libro.portada %} | |||
| <p><img src="{{ libro.portada.url }}" alt="{{ libro.titulo }}" style="width:200px;height:200px;"></p> | |||
| {% else %} | |||
| <p>No hay imágen disponible</p> | |||
| {% endif %} | |||
| {% if libro.archivo %} | |||
| <p><a href="{{ libro.archivo.url }}">Descargar</a></p> | |||
| {% endif %} | |||
| </div><!--//col--> | |||
| <div class="col-12 col-lg-auto text-center text-lg-start"> | |||
| <h4 class="notification-title mb-1">{{ libro.titulo }}</h4> | |||
| <ul class="notification-meta list-inline mb-0"> | |||
| <li class="list-inline-item">{{ libro.autor.nombre }}</li> | |||
| <li class="list-inline-item">|</li> | |||
| <li class="list-inline-item">{{ libro.fecha_publicacion }}</li> | |||
| <li class="list-inline-item">|</li> | |||
| <li class="list-inline-item"><a href="{% url 'libros:detalle_autor' libro.autor_id %}">{{ libro.autor.nombre }}</a></li> | |||
| </ul> | |||
| </div><!--//col--> | |||
| </tr> | |||
| </div><!--//row--> | |||
| </div><!--//app-card-header--> | |||
| </div><!--//app-card--> | |||
| {% endblock %} | |||
| @ -0,0 +1,23 @@ | |||
| {% extends 'base.html' %} | |||
| {% block menuapp %} | |||
| {% include 'libros/_menu-libros.html' %} | |||
| {% endblock menuapp %} | |||
| {% block content %} | |||
| <div class="column is-4 is-offset-4"> | |||
| <h3>{% if form.instance.pk %}Editar Autor{% else %}Nuevo Autor{% endif %}</h3> | |||
| <div class="box"> | |||
| <form method="POST" enctype="multipart/form-data"> | |||
| {% csrf_token %} | |||
| {{ form.as_p }} | |||
| <div class="text mb-3"> | |||
| <button type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto">Guardar</button> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| {% endblock %} | |||
| @ -0,0 +1,22 @@ | |||
| {% extends 'base.html' %} | |||
| {% block menuapp %} | |||
| {% include 'libros/_menu-libros.html' %} | |||
| {% endblock menuapp %} | |||
| {% block content %} | |||
| <div class="column is-4 is-offset-4"> | |||
| <h3>{% if form.instance.pk %}Editar Libro{% else %}Nuevo Libro{% endif %}</h3> | |||
| <div class="box"> | |||
| <form method="POST" enctype="multipart/form-data"> | |||
| {% csrf_token %} | |||
| {{ form.as_p }} | |||
| <div class="text mb-3"> | |||
| <button type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto">Guardar</button> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| {% endblock %} | |||
| @ -0,0 +1,33 @@ | |||
| {% extends 'base.html' %} | |||
| {% block menuapp %} | |||
| {% include 'libros/_menu-libros.html' %} | |||
| {% endblock menuapp %} | |||
| {% 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 gestió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><!--//container-fluid--> | |||
| {% endblock %} | |||
| @ -0,0 +1,77 @@ | |||
| {% extends 'base.html' %} | |||
| {% block menuapp %} | |||
| {% include 'libros/_menu-libros.html' %} | |||
| {% endblock menuapp %} | |||
| {% 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 'libros: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 'libros: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 'libros: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 'libros: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 'libros: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 %} | |||
| @ -0,0 +1,77 @@ | |||
| {% extends 'base.html' %} | |||
| {% block menuapp %} | |||
| {% include 'libros/_menu-libros.html' %} | |||
| {% endblock menuapp %} | |||
| {% 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 'libros: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 'libros: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 'libros: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 'libros: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 %} | |||
| @ -0,0 +1,89 @@ | |||
| {% load i18n static %} | |||
| {% include "_head.html" %} | |||
| <body class="app app-login p-0"> | |||
| <div class="row g-0 app-auth-wrapper"> | |||
| <div class="col-12 col-md-7 col-lg-6 auth-main-col text-center p-5"> | |||
| <div class="d-flex flex-column align-content-end"> | |||
| <div class="app-auth-body mx-auto"> | |||
| {% include "_branding.html" %} | |||
| <h2 class="auth-heading text-center mb-5">Entrar en Finanzas</h2> | |||
| {% if form.errors and not form.non_field_errors %} | |||
| <p class="errornote"> | |||
| {% blocktranslate count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktranslate %} | |||
| </p> | |||
| {% endif %} | |||
| {% if form.non_field_errors %} | |||
| {% for error in form.non_field_errors %} | |||
| <p class="errornote"> | |||
| {{ error }} | |||
| </p> | |||
| {% endfor %} | |||
| {% endif %} | |||
| <div class="auth-form-container text-start" id="content-main"> | |||
| {% if user.is_authenticated %} | |||
| <p class="errornote"> | |||
| {% blocktranslate trimmed %} | |||
| You are authenticated as {{ username }}, but are not authorized to | |||
| access this page. Would you like to login to a different account? | |||
| {% endblocktranslate %} | |||
| </p> | |||
| {% endif %} | |||
| <form class="auth-form login-form" action="{{ app_path }}" method="post" id="login-form">{% csrf_token %} | |||
| <div class="text mb-3"> | |||
| {{ form.username.errors }} | |||
| {{ form.username.label_tag }} | |||
| </div> | |||
| <div class="text mb-3"> | |||
| {{ form.username }} | |||
| </div> | |||
| <div class="password mb-3"> | |||
| {{ form.password.errors }} | |||
| {{ form.password.label_tag }} | |||
| </div> | |||
| <div class="password mb-3"> | |||
| {{ form.password }} | |||
| <input type="hidden" name="next" value="{{ next }}"> | |||
| </div> | |||
| {% url 'admin_password_reset' as password_reset_url %} | |||
| {% if password_reset_url %} | |||
| <div class="password-reset-link"> | |||
| <a href="{{ password_reset_url }}">{% translate 'Forgotten your password or username?' %}</a> | |||
| </div> | |||
| {% endif %} | |||
| <div class="text-center"> | |||
| <input type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto" value="{% translate 'Log in' %}"> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| {% include "_footer.html" %} | |||
| </div> | |||
| </div> | |||
| <div class="col-12 col-md-5 col-lg-6 h-100 auth-background-col"> | |||
| <div class="auth-background-holder"> | |||
| </div> | |||
| <div class="auth-background-mask"></div> | |||
| <div class="auth-background-overlay p-3 p-lg-5"> | |||
| <div class="d-flex flex-column align-content-end h-100"> | |||
| <div class="h-100"></div> | |||
| <!-- | |||
| <div class="overlay-content p-3 p-lg-4 rounded"> | |||
| <h5 class="mb-3 overlay-title">Explore Portal Admin Template</h5> | |||
| <div>Portal is a free Bootstrap 5 admin dashboard template. You can download and view the template license <a href="https://themes.3rdwavemedia.com/bootstrap-templates/admin-dashboard/portal-free-bootstrap-admin-dashboard-template-for-developers/">here</a>.</div> | |||
| </div> | |||
| --> | |||
| </div> | |||
| </div><!--//auth-background-overlay--> | |||
| </div><!--//auth-background-col--> | |||
| </div><!--//row--> | |||
| </body> | |||
| </html> | |||
| @ -0,0 +1,7 @@ | |||
| {% block title %}Logged out{% endblock %} | |||
| {% block content %} | |||
| Logged out | |||
| You have been successfully logged out. You can log-in again. | |||
| {% endblock %} | |||
| @ -0,0 +1,89 @@ | |||
| {% load i18n static %} | |||
| {% include "_head.html" %} | |||
| <body class="app app-login p-0"> | |||
| <div class="row g-0 app-auth-wrapper"> | |||
| <div class="col-12 col-md-7 col-lg-6 auth-main-col text-center p-5"> | |||
| <div class="d-flex flex-column align-content-end"> | |||
| <div class="app-auth-body mx-auto"> | |||
| {% include "_branding.html" %} | |||
| <h2 class="auth-heading text-center mb-5">Entrar en Finanzas</h2> | |||
| {% if form.errors and not form.non_field_errors %} | |||
| <p class="errornote"> | |||
| {% blocktranslate count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktranslate %} | |||
| </p> | |||
| {% endif %} | |||
| {% if form.non_field_errors %} | |||
| {% for error in form.non_field_errors %} | |||
| <p class="errornote"> | |||
| {{ error }} | |||
| </p> | |||
| {% endfor %} | |||
| {% endif %} | |||
| <div class="auth-form-container text-start" id="content-main"> | |||
| {% if user.is_authenticated %} | |||
| <p class="errornote"> | |||
| {% blocktranslate trimmed %} | |||
| You are authenticated as {{ username }}, but are not authorized to | |||
| access this page. Would you like to login to a different account? | |||
| {% endblocktranslate %} | |||
| </p> | |||
| {% endif %} | |||
| <form class="auth-form login-form" action="{{ app_path }}" method="post" id="login-form">{% csrf_token %} | |||
| <div class="text mb-3"> | |||
| {{ form.username.errors }} | |||
| {{ form.username.label_tag }} | |||
| </div> | |||
| <div class="text mb-3"> | |||
| {{ form.username }} | |||
| </div> | |||
| <div class="password mb-3"> | |||
| {{ form.password.errors }} | |||
| {{ form.password.label_tag }} | |||
| </div> | |||
| <div class="password mb-3"> | |||
| {{ form.password }} | |||
| <input type="hidden" name="next" value="{{ next }}"> | |||
| </div> | |||
| {% url 'admin_password_reset' as password_reset_url %} | |||
| {% if password_reset_url %} | |||
| <div class="password-reset-link"> | |||
| <a href="{{ password_reset_url }}">{% translate 'Forgotten your password or username?' %}</a> | |||
| </div> | |||
| {% endif %} | |||
| <div class="text-center"> | |||
| <input type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto" value="{% translate 'Log in' %}"> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| {% include "_footer.html" %} | |||
| </div> | |||
| </div> | |||
| <div class="col-12 col-md-5 col-lg-6 h-100 auth-background-col"> | |||
| <div class="auth-background-holder"> | |||
| </div> | |||
| <div class="auth-background-mask"></div> | |||
| <div class="auth-background-overlay p-3 p-lg-5"> | |||
| <div class="d-flex flex-column align-content-end h-100"> | |||
| <div class="h-100"></div> | |||
| <!-- | |||
| <div class="overlay-content p-3 p-lg-4 rounded"> | |||
| <h5 class="mb-3 overlay-title">Explore Portal Admin Template</h5> | |||
| <div>Portal is a free Bootstrap 5 admin dashboard template. You can download and view the template license <a href="https://themes.3rdwavemedia.com/bootstrap-templates/admin-dashboard/portal-free-bootstrap-admin-dashboard-template-for-developers/">here</a>.</div> | |||
| </div> | |||
| --> | |||
| </div> | |||
| </div><!--//auth-background-overlay--> | |||
| </div><!--//auth-background-col--> | |||
| </div><!--//row--> | |||
| </body> | |||
| </html> | |||
| @ -0,0 +1,10 @@ | |||
| <!DOCTYPE html> | |||
| <html> | |||
| <head> | |||
| <title>Cerrar Sesión</title> | |||
| </head> | |||
| <body> | |||
| <h2>Has cerrado sesión con éxito</h2> | |||
| <a href="{% url 'login' %}">Iniciar sesión nuevamente</a> | |||
| </body> | |||
| </html> | |||
| @ -0,0 +1,67 @@ | |||
| {% include "_head.html" %} | |||
| <body class="app app-signup p-0"> | |||
| <div class="row g-0 app-auth-wrapper"> | |||
| <div class="col-12 col-md-7 col-lg-6 auth-main-col text-center p-5"> | |||
| <div class="d-flex flex-column align-content-end"> | |||
| <div class="app-auth-body mx-auto"> | |||
| {% include "_branding.html" %} | |||
| <h2 class="auth-heading text-center mb-4">Registrarse en Finanzas</h2> | |||
| <div class="auth-form-container text-start mx-auto"> | |||
| <form class="auth-form auth-signup-form" method="POST" enctype="multipart/form-data"> | |||
| {% csrf_token %} | |||
| {% for field in form %} | |||
| <p> | |||
| {{ field.label_tag }}<br> | |||
| {{ field }} | |||
| {% if field.help_text %} | |||
| <small style="color: grey">{{ field.help_text }}</small> | |||
| {% endif %} | |||
| {% for error in field.errors %} | |||
| <p style="color: red">{{ error }}</p> | |||
| {% endfor %} | |||
| </p> | |||
| {% endfor %} | |||
| <div class="item border-bottom py-3"></div> | |||
| <div class="text-center"> | |||
| <button type="submit" class="btn app-btn-primary w-100 theme-btn mx-auto">Sign Up</button> | |||
| </div> | |||
| </form><!--//auth-form--> | |||
| <div class="auth-option text-center pt-5">¿Ya tienes una cuenta? <a class="text-link" href="{% url 'login' %}" >Entra</a></div> | |||
| </div><!--//auth-form-container--> | |||
| </div><!--//auth-body--> | |||
| {% include "_footer.html" %} | |||
| </div><!--//flex-column--> | |||
| </div><!--//auth-main-col--> | |||
| <div class="col-12 col-md-5 col-lg-6 h-100 auth-background-col"> | |||
| <div class="auth-background-holder"> | |||
| </div> | |||
| <div class="auth-background-mask"></div> | |||
| <div class="auth-background-overlay p-3 p-lg-5"> | |||
| <div class="d-flex flex-column align-content-end h-100"> | |||
| <div class="h-100"></div> | |||
| <!-- | |||
| <div class="overlay-content p-3 p-lg-4 rounded"> | |||
| <h5 class="mb-3 overlay-title">Explore Portal Admin Template</h5> | |||
| <div>Portal is a free Bootstrap 5 admin dashboard template. You can download and view the template license <a href="https://themes.3rdwavemedia.com/bootstrap-templates/admin-dashboard/portal-free-bootstrap-admin-dashboard-template-for-developers/">here</a>.</div> | |||
| </div> | |||
| --> | |||
| </div> | |||
| </div><!--//auth-background-overlay--> | |||
| </div><!--//auth-background-col--> | |||
| </div><!--//row--> | |||
| </body> | |||
| </html> | |||
| @ -0,0 +1,4 @@ | |||
| FROM nginx:1.25 | |||
| RUN rm /etc/nginx/conf.d/default.conf | |||
| COPY nginx.conf /etc/nginx/conf.d | |||
| @ -0,0 +1,8 @@ | |||
| install: | |||
| echo "Creando imagen con version '${IMG_NGINX_VERSION}' para la arquitectura '${ARQUITECTURA}' en el registry '${REGISTRY}'" | |||
| docker build --no-cache -t ${REGISTRY}/nginx-reymota-${ARQUITECTURA}:${IMG_NGINX_VERSION} . | |||
| docker push ${REGISTRY}/nginx-reymota-${ARQUITECTURA}:${IMG_NGINX_VERSION} | |||
| @ -0,0 +1,25 @@ | |||
| upstream reymota { | |||
| server reymota:8000; | |||
| } | |||
| server { | |||
| listen 80; | |||
| location / { | |||
| proxy_pass http://reymota; | |||
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |||
| proxy_set_header Host $http_host; | |||
| proxy_redirect off; | |||
| client_max_body_size 100M; | |||
| } | |||
| location /static/ { | |||
| alias /app/reymota/staticfiles/; | |||
| } | |||
| location /media/ { | |||
| alias /app/reymota/mediafiles/; | |||
| } | |||
| } | |||
| @ -0,0 +1,13 @@ | |||
| asgiref==3.8.1 | |||
| Django==4.2 | |||
| flake8==7.1.1 | |||
| gunicorn==22.0.0 | |||
| mccabe==0.7.0 | |||
| packaging==24.1 | |||
| pillow==10.4.0 | |||
| psycopg2-binary==2.9.6 | |||
| pycodestyle==2.12.1 | |||
| pyflakes==3.2.0 | |||
| sqlparse==0.5.1 | |||
| typing_extensions==4.12.2 | |||
| django-calculation==1.0.0 | |||