Celestino Rey 1 год назад
Родитель
Сommit
0fc59d212f
100 измененных файлов с 1129 добавлено и 38 удалено
  1. 40 0
      Dockerfile
  2. 61 0
      Dockerfile.k8s
  3. 56 0
      K8S/Makefile
  4. 2 0
      K8S/borraNS.sh
  5. 5 0
      K8S/creaDirs.sh
  6. 52 0
      K8S/db-deployment.yaml
  7. 17 0
      K8S/db-service.yaml
  8. 1 0
      K8S/entra.sh
  9. 1 0
      K8S/entraPsql.sh
  10. 15 0
      K8S/env-prod-configmap.yaml
  11. 11 0
      K8S/env-prod-db-configmap.yaml
  12. 105 0
      K8S/finanzas-deployment.yaml
  13. 31 0
      K8S/finanzas-ingress.yaml
  14. 47 0
      K8S/finanzas-prod-persistentvolumeclaim.yaml
  15. 7 0
      K8S/namespace.yaml
  16. 46 0
      K8S/nginx-deployment.yaml
  17. 20 0
      K8S/nginx-service.yaml
  18. 13 0
      K8S/postgres-data-persistentvolumeclaim.yaml
  19. 74 0
      K8S/pv-local-finanzas.yaml
  20. 8 0
      K8S/reg-secret.yaml
  21. 13 0
      K8S/static-volume-persistentvolumeclaim.yaml
  22. 8 0
      Makefile
  23. 98 0
      README.md
  24. 5 0
      Shells/asignaPVC.sh
  25. 3 0
      Shells/borraDB.sh
  26. 4 0
      Shells/creaDB.sh
  27. 1 0
      Shells/entra.sh
  28. 1 0
      Shells/nuevaapp.sh
  29. 11 0
      Yamls/env-prod-db-configmap.yaml
  30. 52 0
      Yamls/postgresql-deployment.yaml
  31. 17 0
      Yamls/postgresql-service.yaml
  32. 17 0
      Yamls/pvc-postgresql.yaml
  33. 15 0
      Yamls/reymota-service.yaml
  34. BIN
      db.sqlite3
  35. 20 0
      entrypoint.sh
  36. 0 1
      finanzas/.gitignore
  37. BIN
      finanzas/migrations/__pycache__/0001_initial.cpython-312.pyc
  38. BIN
      finanzas/migrations/__pycache__/0002_remove_movimiento_categoria_cuenta_and_more.cpython-312.pyc
  39. BIN
      finanzas/migrations/__pycache__/0003_cuenta_favorita.cpython-312.pyc
  40. BIN
      finanzas/migrations/__pycache__/__init__.cpython-312.pyc
  41. 0 2
      misfinanzas/views.py
  42. 32 0
      nginx/default.conf
  43. BIN
      reymotausers/management/__pycache__/__init__.cpython-312.pyc
  44. BIN
      reymotausers/migrations/__pycache__/0001_initial.cpython-312.pyc
  45. BIN
      reymotausers/migrations/__pycache__/__init__.cpython-312.pyc
  46. 0 0
      src/accounts/__init__.py
  47. 0 0
      src/accounts/admin.py
  48. 0 0
      src/accounts/apps.py
  49. 0 0
      src/accounts/models.py
  50. 0 0
      src/accounts/tests.py
  51. 1 1
      src/accounts/urls.py
  52. 1 1
      src/accounts/views.py
  53. 27 0
      src/config/entrypoint.sh
  54. 0 0
      src/finanzas/__init__.py
  55. 1 1
      src/finanzas/admin.py
  56. 0 0
      src/finanzas/apps.py
  57. 4 3
      src/finanzas/forms.py
  58. 0 0
      src/finanzas/migrations/0001_initial.py
  59. 0 0
      src/finanzas/migrations/0002_initial.py
  60. 0 0
      src/finanzas/migrations/0003_alter_movimiento_fecha.py
  61. 0 0
      src/finanzas/migrations/0004_movimientofrecuente.py
  62. 0 0
      src/finanzas/migrations/__init__.py
  63. 3 0
      src/finanzas/models.py
  64. 0 0
      src/finanzas/tests.py
  65. 0 2
      src/finanzas/urls.py
  66. 11 17
      src/finanzas/views.py
  67. 0 0
      src/manage.py
  68. 0 0
      src/misfinanzas/__init__.py
  69. 0 0
      src/misfinanzas/asgi.py
  70. 13 0
      src/misfinanzas/context_processors.py
  71. 87 7
      src/misfinanzas/settings.py
  72. 0 0
      src/misfinanzas/templatetags/__init__.py
  73. 9 0
      src/misfinanzas/templatetags/filtros_de_entorno.py
  74. 3 3
      src/misfinanzas/urls.py
  75. 40 0
      src/misfinanzas/views.py
  76. 0 0
      src/misfinanzas/wsgi.py
  77. 0 0
      src/profile_images/Imagen_generada.jpeg
  78. 0 0
      src/profile_images/Imagen_generada_jZWkGR5.jpeg
  79. 0 0
      src/profile_images/default.jpg
  80. 20 0
      src/requirements.txt
  81. 0 0
      src/reymotausers/__init__.py
  82. 0 0
      src/reymotausers/admin.py
  83. 0 0
      src/reymotausers/apps.py
  84. 0 0
      src/reymotausers/forms.py
  85. 0 0
      src/reymotausers/management/__init__.py
  86. 0 0
      src/reymotausers/management/commands/__init__.py
  87. 0 0
      src/reymotausers/management/commands/importar_usuarios.py
  88. 0 0
      src/reymotausers/managers.py
  89. 0 0
      src/reymotausers/migrations/0001_initial.py
  90. 0 0
      src/reymotausers/migrations/__init__.py
  91. 0 0
      src/reymotausers/models.py
  92. 0 0
      src/reymotausers/serializers.py
  93. 0 0
      src/reymotausers/tests.py
  94. 0 0
      src/reymotausers/urls.py
  95. 0 0
      src/reymotausers/views.py
  96. 0 0
      src/static/bootstrap/css/bootstrap-icons.css
  97. 0 0
      src/static/bootstrap/css/bootstrap.min.css
  98. 0 0
      src/static/bootstrap/css/bootstrap.min.css.map
  99. 0 0
      src/static/bootstrap/css/fonts/bootstrap-icons.woff
  100. 0 0
      src/static/bootstrap/css/fonts/bootstrap-icons.woff2

+ 40 - 0
Dockerfile

@@ -0,0 +1,40 @@
+# yup, python 3.11!
+FROM python:3.11-slim
+
+# install nginx y otras cosas
+RUN apt-get update && apt-get install nginx netcat-openbsd curl vim jq rsync -y
+
+# copy our nginx configuration to overwrite nginx defaults
+RUN rm /etc/nginx/sites-enabled/default
+RUN rm /etc/nginx/sites-available/default
+COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
+# link nginx logs to container stdout
+RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log
+
+# copy the django code
+COPY ./src ./app
+
+RUN chgrp -R 0 ./app && chmod -R g=u ./app
+RUN chgrp -R 0 /var/lib/nginx && chmod -R g=u /var/lib/nginx
+
+# change our working directory to the django projcet roo
+WORKDIR /app
+
+# create virtual env (notice the location?)
+# update pip
+# install requirements
+RUN python -m venv /opt/venv && \
+    /opt/venv/bin/python -m pip install pip --upgrade && \
+    /opt/venv/bin/python -m pip install -r requirements.txt
+
+# Añade path a .bashrc
+
+RUN echo "export PATH=/opt/venv/bin/:$PATH" >> /root/.bashrc
+
+# make our entrypoint.sh executable
+RUN chmod +x config/entrypoint.sh
+
+#EXPOSE 8080
+
+# execute our entrypoint.sh file
+CMD ["./config/entrypoint.sh"]

+ 61 - 0
Dockerfile.k8s

@@ -0,0 +1,61 @@
+# syntax=docker/dockerfile:1
+##################
+# BUILDER        #
+##################
+
+FROM python:3.11.4-slim-buster AS builder
+
+# set work directory
+WORKDIR /app
+
+# set environment variables
+ENV PYTHONDONTWRITEBYTECODE=1
+ENV PYTHONUNBUFFERED=1
+
+# install system dependencies
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends gcc
+
+# lint
+RUN pip install --upgrade pip
+RUN pip install flake8==6.0.0
+COPY . /app/
+RUN flake8 --ignore=E501,F401,E126 .
+
+COPY ./src/requirements.txt .
+
+
+RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
+
+##################
+# FINAL          #
+##################
+
+FROM python:3.11.4-slim-buster
+
+# create the appropriate directories
+ENV APP_HOME=/app
+RUN mkdir -p $APP_HOME
+
+WORKDIR $APP_HOME
+
+# install system dependencies
+RUN apt-get update && apt-get install -y sqlite3 netcat vim procps curl jq
+COPY --from=builder /app/wheels /wheels
+COPY --from=builder /app/requirements.txt .
+
+RUN pip install --upgrade pip
+RUN pip install --no-cache /wheels/*
+
+# copy entrypoint.sh
+COPY ./entrypoint.sh .
+
+# copy project
+COPY . $APP_HOME
+
+# change to the app user
+
+WORKDIR $APP_HOME/src
+
+# run entrypoint.sh
+ENTRYPOINT ["/app/entrypoint.sh"]

+ 56 - 0
K8S/Makefile

@@ -0,0 +1,56 @@
+export ARQUITECTURA := $(shell lscpu |grep itectur | tr -d ' '| cut -f2 -d':')
+export REGISTRY=registry.reymota.es
+export IMG_VERSION = 0.11
+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-finanzas.yaml
+	-kubectl create -f finanzas-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 < finanzas-deployment.yaml |kubectl create -f -
+	-envsubst < nginx-deployment.yaml |kubectl create -f -
+	-kubectl create -f nginx-service.yaml
+	-kubectl create -f finanzas-ingress.yaml
+
+clean:
+	-envsubst < nginx-deployment.yaml |kubectl delete -f -
+	-kubectl delete -f nginx-service.yaml
+	-envsubst < finanzas-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 finanzas-prod-persistentvolumeclaim.yaml
+	-kubectl delete -f pv-local-finanzas.yaml
+	-kubectl delete -f reg-secret.yaml
+	-kubectl delete -f namespace.yaml
+
+nginx:
+	cd ../nginx; make
+
+backup:
+	kubectl --kubeconfig /home/creylopez/.kube/config -n finanzas exec -ti deployment.apps/db -- /usr/lib/postgresql/15/bin/pg_dump --username=creylopez --dbname=finanzas > finanzas-$(IMG_VERSION).sql
+
+muestra:
+	-envsubst < finanzas-deployment.yaml > /tmp/deployment.yaml

+ 2 - 0
K8S/borraNS.sh

@@ -0,0 +1,2 @@
+( NAMESPACE=finanzas; kubectl proxy & kubectl get namespace $NAMESPACE -o json |jq '.spec = {"finalizers":[]}' >temp.json; curl -k -H "Content-Type: application/json" -X PUT --data-binary @temp.json 127.0.0.1:8001/api/v1/namespaces/$NAMESPACE/finalize; )
+

+ 5 - 0
K8S/creaDirs.sh

@@ -0,0 +1,5 @@
+sudo mkdir -p /mnt/Externo/finanzas/media
+sudo mkdir -p /mnt/Externo/finanzas/migrations/finanzas
+sudo mkdir -p /mnt/Externo/finanzas/migrations/reymotausers
+sudo mkdir -p /mnt/Externo/finanzas/static
+sudo mkdir -p /mnt/Externo/finanzas/pg

+ 52 - 0
K8S/db-deployment.yaml

@@ -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: postgresql
+  name: postgresql
+  namespace: finanzas
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      io.kompose.service: postgresql
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      annotations:
+        kompose.cmd: kompose convert
+        kompose.version: 1.34.0 (cbf2835db)
+      labels:
+        io.kompose.service: postgresql
+    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: postgresql
+          volumeMounts:
+            - mountPath: /var/lib/postgresql/data
+              name: postgres-data
+      restartPolicy: Always
+      volumes:
+        - name: postgres-data
+          persistentVolumeClaim:
+            claimName: postgres-data

+ 17 - 0
K8S/db-service.yaml

@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: Service
+metadata:
+  annotations:
+    kompose.cmd: kompose convert
+    kompose.version: 1.34.0 (cbf2835db)
+  labels:
+    io.kompose.service: postgresql
+  name: postgresql
+  namespace: finanzas
+spec:
+  ports:
+    - name: "5432"
+      port: 5432
+      targetPort: 5432
+  selector:
+    io.kompose.service: postgresql

+ 1 - 0
K8S/entra.sh

@@ -0,0 +1 @@
+kubectl -n finanzas exec -ti deployment.apps/finanzas -- /bin/bash

+ 1 - 0
K8S/entraPsql.sh

@@ -0,0 +1 @@
+kubectl -n finanzas exec -ti deployment.apps/postgresql -- psql --username=creylopez --dbname=finanzas

+ 15 - 0
K8S/env-prod-configmap.yaml

@@ -0,0 +1,15 @@
+apiVersion: v1
+data:
+  DEBUG: "False"
+  ENTORNO: "Producción"
+  APP_VERSION: 15.0.3
+  SECRET_KEY: change_me
+  SQL_HOST: postgresql
+  SQL_PORT: "5432"
+  DATABASE: postgres
+kind: ConfigMap
+metadata:
+  labels:
+    io.kompose.service: web-env-prod
+  name: env-prod
+  namespace: finanzas

+ 11 - 0
K8S/env-prod-db-configmap.yaml

@@ -0,0 +1,11 @@
+apiVersion: v1
+data:
+  POSTGRES_DB: finanzas
+  POSTGRES_PASSWORD: Dsa-0213
+  POSTGRES_USER: creylopez
+kind: ConfigMap
+metadata:
+  labels:
+    io.kompose.service: db-env-prod-db
+  name: env-prod-db
+  namespace: finanzas

+ 105 - 0
K8S/finanzas-deployment.yaml

@@ -0,0 +1,105 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: finanzas
+  namespace: finanzas
+spec:
+  ports:
+    - name: "8000"
+      port: 8000
+      targetPort: 8000
+  selector:
+    app: finanzas
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: finanzas
+  namespace: finanzas
+  labels:
+    app: finanzas
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: finanzas
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        app: finanzas
+    spec:
+      containers:
+      - args:
+          - gunicorn
+          - misfinanzas.wsgi:application
+          - --bind
+          - 0.0.0.0:8000
+        name: finanzas
+        image: $REGISTRY/finanzas-$ARQUITECTURA:$IMG_VERSION
+        env:
+        - name: IMG_VERSION
+          value: "$IMG_VERSION"
+        - name: OPENSHIFT
+          value: "False"
+        - name: ENVIRONMENT
+          valueFrom:
+            configMapKeyRef:
+              key: ENTORNO
+              name: env-prod
+        - name: DEBUG
+          valueFrom:
+            configMapKeyRef:
+              key: DEBUG
+              name: env-prod
+        - name: APP_VERSION
+          valueFrom:
+            configMapKeyRef:
+              key: APP_VERSION
+              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
+        ports:
+        - containerPort: 8000
+          protocol: TCP
+        volumeMounts:
+        - mountPath: /app/src/mediafiles
+          name: finanzas-media
+        - mountPath: /app/src/finanzas/migrations
+          name: finanzas-finanzas-migrations
+        - mountPath: /app/src/reymotausers/migrations
+          name: finanzas-reymotausers-migrations
+
+        - mountPath: /app/src/staticfiles
+          name: static-volume
+      imagePullSecrets:
+      - name: myregistrykey
+      restartPolicy: Always
+      volumes:
+      - name: finanzas-media
+        persistentVolumeClaim:
+          claimName: finanzas-media
+      - name: finanzas-finanzas-migrations
+        persistentVolumeClaim:
+          claimName: finanzas-finanzas-migrations
+      - name: finanzas-reymotausers-migrations
+        persistentVolumeClaim:
+          claimName: finanzas-reymotausers-migrations
+      - name: static-volume
+        persistentVolumeClaim:
+          claimName: static-volume
+status: {}

+ 31 - 0
K8S/finanzas-ingress.yaml

@@ -0,0 +1,31 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  generation: 1
+  managedFields:
+    - apiVersion: networking.k8s.io/v1
+      fieldsType: FieldsV1
+      fieldsV1:
+        f:spec:
+          f:defaultBackend:
+            .: {}
+            f:service:
+              .: {}
+              f:name: {}
+              f:port: {}
+          f:rules: {}
+      manager: rancher
+      operation: Update
+  name: finanzas
+  namespace: finanzas
+spec:
+  defaultBackend:
+    service:
+      name: nginx
+      port:
+        number: 1337
+  ingressClassName: nginx
+  rules:
+    - host: finanzas.rancher.reymota.lab
+status:
+  loadBalancer: {}

+ 47 - 0
K8S/finanzas-prod-persistentvolumeclaim.yaml

@@ -0,0 +1,47 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  creationTimestamp: null
+  labels:
+    io.kompose.service: finanzas-media
+  name: finanzas-media
+  namespace: finanzas
+spec:
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 100Mi
+status: {}
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  creationTimestamp: null
+  labels:
+    io.kompose.service: finanzas-reymotausers-migrations
+  name: finanzas-reymotausers-migrations
+  namespace: finanzas
+spec:
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 53Mi
+status: {}
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  creationTimestamp: null
+  labels:
+    io.kompose.service: finanzas-finanzas-migrations
+  name: finanzas-finanzas-migrations
+  namespace: finanzas
+spec:
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 52Mi
+status: {}

+ 7 - 0
K8S/namespace.yaml

@@ -0,0 +1,7 @@
+###################################################
+# Namespace finanzas
+###################################################
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: finanzas

+ 46 - 0
K8S/nginx-deployment.yaml

@@ -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: finanzas
+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-finanzas-$ARQUITECTURA:$IMG_NGINX_VERSION
+          name: nginx
+          ports:
+            - containerPort: 80
+              protocol: TCP
+          volumeMounts:
+            - mountPath: /app/finanzas/staticfiles
+              name: static-volume
+            - mountPath: /app/finanzas/mediafiles
+              name: finanzas-media
+      imagePullSecrets:
+      - name: myregistrykey
+      restartPolicy: Always
+      volumes:
+        - name: static-volume
+          persistentVolumeClaim:
+            claimName: static-volume
+        - name: finanzas-media
+          persistentVolumeClaim:
+            claimName: finanzas-media

+ 20 - 0
K8S/nginx-service.yaml

@@ -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: finanzas
+spec:
+  type: NodePort
+  ports:
+    - name: "1337"
+      port: 1337
+      nodePort: 30342
+      targetPort: 80
+  selector:
+    io.kompose.service: nginx
+

+ 13 - 0
K8S/postgres-data-persistentvolumeclaim.yaml

@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  labels:
+    io.kompose.service: postgres-data
+  name: postgres-data
+  namespace: finanzas
+spec:
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 100Mi

+ 74 - 0
K8S/pv-local-finanzas.yaml

@@ -0,0 +1,74 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+  name: finanzas-media-folder
+  namespace: finanzas
+  labels:
+    app: finanzas
+spec:
+  capacity:
+    storage: 100Mi
+  accessModes:
+    - ReadWriteOnce
+  hostPath:
+    path: "/mnt/Externo/finanzas/media"
+---
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+  name: finanzas-finanzas-migrations-folder
+  namespace: finanzas
+  labels:
+    app: finanzas
+spec:
+  capacity:
+    storage: 52Mi
+  accessModes:
+    - ReadWriteOnce
+  hostPath:
+    path: "/mnt/Externo/finanzas/migrations/finanzas"
+---
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+  name: finanzas-reymotausers-migrations-folder
+  namespace: finanzas
+  labels:
+    app: finanzas
+spec:
+  capacity:
+    storage: 53Mi
+  accessModes:
+    - ReadWriteOnce
+  hostPath:
+    path: "/mnt/Externo/finanzas/migrations/reymotausers"
+---
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+  name: finanzas-static-folder
+  namespace: finanzas
+  labels:
+    app: finanzas
+spec:
+  capacity:
+    storage: 70Mi
+  accessModes:
+    - ReadWriteOnce
+  hostPath:
+    path: "/mnt/Externo/finanzas/static"
+---
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+  name: finanzas-pg-folder
+  namespace: finanzas
+  labels:
+    app: finanzas
+spec:
+  capacity:
+    storage: 200Mi
+  accessModes:
+    - ReadWriteOnce
+  hostPath:
+    path: "/mnt/Externo/finanzas/pg"

+ 8 - 0
K8S/reg-secret.yaml

@@ -0,0 +1,8 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name: myregistrykey
+  namespace: finanzas
+data:
+  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJyZWdpc3RyeS5yZXltb3RhLmVzIjogewoJCQkiYXV0aCI6ICJZM0psZVd4dmNHVjZPbEpsZVMweE1UYzIiCgkJfQoJfQp9
+type: kubernetes.io/dockerconfigjson

+ 13 - 0
K8S/static-volume-persistentvolumeclaim.yaml

@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  labels:
+    io.kompose.service: static-volume
+  name: static-volume
+  namespace: finanzas
+spec:
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: 70Mi

+ 8 - 0
Makefile

@@ -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}/finanzas-${ARQUITECTURA}:${IMG_VERSION} -f Dockerfile.k8s .
+	docker push ${REGISTRY}/finanzas-${ARQUITECTURA}:${IMG_VERSION}
+
+

+ 98 - 0
README.md

@@ -0,0 +1,98 @@
+# Versión para openshift
+
+## Instalación
+
+Crear un proyecto.
+
+### Running Commands as Root in OpenShift
+
+    oc adm policy add-scc-to-user anyuid -z default
+    
+### app reymota
+
+A continuación añadir una app desde Agregar, importar desde git.
+
+    oc new-app http://gitea.reymota.es/creylopez/ReyMotaAppsOC.git -e APP_VERSION="15.0.0" -e DEBUG="False" -e OPENSHIFT="True" --name='reymota'
+
+Tal y como está la estructura de directorios, deberia detectar automáticamente una compilación Python
+
+## asignación de los volúmenes
+### Si la pvc no está creada
+
+    oc set volume deployment.apps/reymota --add -t pvc --claim-size=300M --name=reymota-lyrics-migrations --claim-name='reymota-lyrics-migrations' --mount-path='/app/lyrics/migrations'
+    oc set volume deployment.apps/reymota --add -t pvc --claim-size=300M --name=reymota-media --claim-name='reymota-media' --mount-path='/app/mediafiles'
+    oc set volume deployment.apps/reymota --add -t pvc --claim-size=300M --name=reymota-repostajes-migrations --claim-name='reymota-repostajes-migrations' --mount-path='/app/repostajes/migrations'
+    oc set volume deployment.apps/reymota --add -t pvc --claim-size=300M --name=reymota-reymotausers-migrations --claim-name='reymota-reymotausers-migrations' --mount-path='/app/reymotausers/migrations'
+    oc set volume deployment.apps/reymota --add -t pvc --claim-size=50G --name=static-volume --claim-name='static-volume' --mount-path='/app/staticfiles'
+     
+ 
+### Si la pvc ya está creada
+
+    oc set volume deployment.apps/reymota --add -t pvc --name=reymota-lyrics-migrations --claim-name='reymota-lyrics-migrations' --mount-path='/app/lyrics/migrations'
+    oc set volume deployment.apps/reymota --add -t pvc --name=reymota-media --claim-name='reymota-media' --mount-path='/app/mediafiles'
+    oc set volume deployment.apps/reymota --add -t pvc --name=reymota-repostajes-migrations --claim-name='reymota-repostajes-migrations' --mount-path='/app/repostajes/migrations'
+    oc set volume deployment.apps/reymota --add -t pvc --name=reymota-reymotausers-migrations --claim-name='reymota-reymotausers-migrations' --mount-path='/app/reymotausers/migrations'
+    oc set volume deployment.apps/reymota --add -t pvc --name=static-volume --claim-name='static-volume' --mount-path='/app/staticfiles'
+
+
+## Exponer el servicio
+    oc expose deployment.apps/reymota --type=NodePort --port=8080
+    
+### postgresql
+Se hace desde el yaml
+
+    oc create -f postgresql-deployment.yaml
+
+
+## Modificaciones al código
+
+Una vez realizadas las modificaciones al código y se hayan subido a gitea, hay que reconstruir el proyecto.
+
+    oc start-build reymota
+
+## Comandos a ejecutar la primera vez o cuando haya cambios en las bases de datos
+
+    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.
+

+ 5 - 0
Shells/asignaPVC.sh

@@ -0,0 +1,5 @@
+
+oc set volume deployment.apps/finanzas --add -t pvc --name=finanzas-media --claim-name='finanzas-media' --mount-path='/app/mediafiles'
+oc set volume deployment.apps/finanzas --add -t pvc --name=finanzas-finanzas-migrations --claim-name='finanzas-finanzas-migrations' --mount-path='/app/finanzas/migrations'
+oc set volume deployment.apps/finanzas --add -t pvc --name=finanzas-reymotausers-migrations --claim-name='finanzas-reymotausers-migrations' --mount-path='/app/reymotausers/migrations'
+oc set volume deployment.apps/finanzas --add -t pvc --name=static-volume --claim-name='static-volume' --mount-path='/app/staticfiles'

+ 3 - 0
Shells/borraDB.sh

@@ -0,0 +1,3 @@
+oc delete -f Yamls/env-prod-db-configmap.yaml
+oc delete -f Yamls/postgresql-deployment.yaml
+oc delete -f Yamls/postgresql-service.yaml

+ 4 - 0
Shells/creaDB.sh

@@ -0,0 +1,4 @@
+oc create -f Yamls/env-prod-db-configmap.yaml
+#oc create -f Yamls/pvc-postgresql.yaml
+oc create -f Yamls/postgresql-deployment.yaml
+oc create -f Yamls/postgresql-service.yaml

+ 1 - 0
Shells/entra.sh

@@ -0,0 +1 @@
+oc exec -it deployment.apps/finanzasappsoc -- bash

+ 1 - 0
Shells/nuevaapp.sh

@@ -0,0 +1 @@
+oc new-app http://forgejo.reymota.es/creylopez/misfinanzas.git -e DEBUG="False" --name='finanzas'

+ 11 - 0
Yamls/env-prod-db-configmap.yaml

@@ -0,0 +1,11 @@
+apiVersion: v1
+data:
+  POSTGRES_DB: finanzas
+  POSTGRES_PASSWORD: Dsa-0213
+  POSTGRES_USER: creylopez
+kind: ConfigMap
+metadata:
+  labels:
+    io.kompose.service: db-env-prod-db
+  name: env-prod-db
+  namespace: finanzas

+ 52 - 0
Yamls/postgresql-deployment.yaml

@@ -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: postgresql
+  name: postgresql
+  namespace: finanzas
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      io.kompose.service: postgresql
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      annotations:
+        kompose.cmd: kompose convert
+        kompose.version: 1.34.0 (cbf2835db)
+      labels:
+        io.kompose.service: postgresql
+    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: postgresql
+          volumeMounts:
+            - mountPath: /var/lib/postgresql/data
+              name: postgresql
+      restartPolicy: Always
+      volumes:
+        - name: postgresql
+          persistentVolumeClaim:
+            claimName: postgresql

+ 17 - 0
Yamls/postgresql-service.yaml

@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: Service
+metadata:
+  annotations:
+    kompose.cmd: kompose convert
+    kompose.version: 1.34.0 (cbf2835db)
+  labels:
+    io.kompose.service: postgresql
+  name: postgresql
+  namespace: finanzas
+spec:
+  ports:
+    - name: "5432"
+      port: 5432
+      targetPort: 5432
+  selector:
+    io.kompose.service: postgresql

+ 17 - 0
Yamls/pvc-postgresql.yaml

@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  finalizers:
+  - kubernetes.io/pvc-protection
+  labels:
+    template: postgresql-persistent-template
+  name: postgresql
+  namespace: finanzas
+spec:
+  accessModes:
+  - ReadWriteOnce
+  resources:
+    requests:
+      storage: 1Gi
+  storageClassName: lvms-vg1
+  volumeMode: Filesystem

+ 15 - 0
Yamls/reymota-service.yaml

@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: finanzas
+  namespace: finanzas
+spec:
+  type: LoadBalancer
+  ports:
+    - name: "8080"
+      port: 8080
+      nodePort: 30341
+      targetPort: 8080
+  selector:
+    deployment: finanzas
+


+ 20 - 0
entrypoint.sh

@@ -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 - 1
finanzas/.gitignore

@@ -1 +0,0 @@
-__pycache__/

BIN
finanzas/migrations/__pycache__/0001_initial.cpython-312.pyc


BIN
finanzas/migrations/__pycache__/0002_remove_movimiento_categoria_cuenta_and_more.cpython-312.pyc


BIN
finanzas/migrations/__pycache__/0003_cuenta_favorita.cpython-312.pyc


BIN
finanzas/migrations/__pycache__/__init__.cpython-312.pyc


+ 0 - 2
misfinanzas/views.py

@@ -1,2 +0,0 @@
-from django.shortcuts import render, get_object_or_404
-

+ 32 - 0
nginx/default.conf

@@ -0,0 +1,32 @@
+upstream django_project {
+    server localhost:8000;
+}
+
+error_log /var/log/nginx/error.log;
+
+server {
+    listen       8080;
+
+    access_log /var/log/nginx/access.log;
+
+    location / {
+        proxy_pass http://django_project;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header Host $host;
+        proxy_redirect off;
+        client_max_body_size 100M;
+    }
+
+    location /static/ {
+        alias /app/staticfiles/;
+    }
+
+    location /media/ {
+        alias /app/mediafiles/;
+    }
+
+    error_page   500 502 503 504  /50x.html;
+    location = /50x.html {
+        root   /usr/share/nginx/html;
+    }
+}

BIN
reymotausers/management/__pycache__/__init__.cpython-312.pyc


BIN
reymotausers/migrations/__pycache__/0001_initial.cpython-312.pyc


BIN
reymotausers/migrations/__pycache__/__init__.cpython-312.pyc


+ 0 - 0
accounts/__init__.py → src/accounts/__init__.py


+ 0 - 0
accounts/admin.py → src/accounts/admin.py


+ 0 - 0
accounts/apps.py → src/accounts/apps.py


+ 0 - 0
accounts/models.py → src/accounts/models.py


+ 0 - 0
accounts/tests.py → src/accounts/tests.py


+ 1 - 1
accounts/urls.py → src/accounts/urls.py

@@ -11,4 +11,4 @@ urlpatterns = [
     path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
     path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
     path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
-]
+]

+ 1 - 1
accounts/views.py → src/accounts/views.py

@@ -9,4 +9,4 @@ from reymotausers.forms import ReyMotaUserCreationForm
 class SignUpView(CreateView):
     form_class = ReyMotaUserCreationForm
     success_url = reverse_lazy("login")
-    template_name = "registration/signup.html"
+    template_name = "registration/signup.html"

+ 27 - 0
src/config/entrypoint.sh

@@ -0,0 +1,27 @@
+#!/bin/bash
+RUN_PORT="8000"
+DATABASE=postgres
+SQL_HOST=postgresql
+SQL_PORT=5432
+
+export PATH=/opt/venv/bin:$PATH
+
+if [ "$DATABASE" = "postgres" ]
+then
+    echo "Waiting for postgres..."
+
+    while ! nc -z $SQL_HOST $SQL_PORT; do
+      sleep 0.1
+    done
+
+    echo "PostgreSQL started"
+
+	/opt/venv/bin/python manage.py migrate --no-input
+	/opt/venv/bin/python manage.py collectstatic --no-input
+
+	/opt/venv/bin/gunicorn misfinanzas.wsgi:application --bind "0.0.0.0:${RUN_PORT}" --daemon
+
+	nginx -g 'daemon off;'
+else
+    echo "la base de datos no es postgres: '$DATABASE'"
+fi

+ 0 - 0
finanzas/__init__.py → src/finanzas/__init__.py


+ 1 - 1
finanzas/admin.py → src/finanzas/admin.py

@@ -5,4 +5,4 @@ from .models import Movimiento, Cuenta, MovimientoFrecuente
 
 admin.site.register(Movimiento)
 admin.site.register(Cuenta)
-admin.site.register(MovimientoFrecuente)
+admin.site.register(MovimientoFrecuente)

+ 0 - 0
finanzas/apps.py → src/finanzas/apps.py


+ 4 - 3
finanzas/forms.py → src/finanzas/forms.py

@@ -39,10 +39,11 @@ class MovimientoForm(forms.ModelForm):
         except InvalidOperation:
             raise forms.ValidationError("Introduzca un número válido. Puede usar coma o punto como separador decimal.")
 
+
 class FiltroForm(forms.Form):
-#    fecha_inicio = forms.DateField(required=False, widget=forms.DateInput(attrs={'type': 'date'}))
-#    fecha_fin = forms.DateField(required=False, widget=forms.DateInput(attrs={'type': 'date'}))
-#    cuenta = forms.ModelChoiceField(queryset=Cuenta.objects.all(), required=False)
+    #    fecha_inicio = forms.DateField(required=False, widget=forms.DateInput(attrs={'type': 'date'}))
+    #    fecha_fin = forms.DateField(required=False, widget=forms.DateInput(attrs={'type': 'date'}))
+    #    cuenta = forms.ModelChoiceField(queryset=Cuenta.objects.all(), required=False)
     buscar = forms.CharField(required=False, label='',
                              widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Buscar...'}))
 

+ 0 - 0
finanzas/migrations/0001_initial.py → src/finanzas/migrations/0001_initial.py


+ 0 - 0
finanzas/migrations/0002_initial.py → src/finanzas/migrations/0002_initial.py


+ 0 - 0
finanzas/migrations/0003_alter_movimiento_fecha.py → src/finanzas/migrations/0003_alter_movimiento_fecha.py


+ 0 - 0
finanzas/migrations/0004_movimientofrecuente.py → src/finanzas/migrations/0004_movimientofrecuente.py


+ 0 - 0
finanzas/migrations/__init__.py → src/finanzas/migrations/__init__.py


+ 3 - 0
finanzas/models.py → src/finanzas/models.py

@@ -1,6 +1,7 @@
 from django.db import models
 from reymotausers.models import ReyMotaUser
 
+
 class Cuenta(models.Model):
     TIPO_CUENTA_CHOICES = (
         ('ingreso', 'Ingreso'),
@@ -15,6 +16,7 @@ class Cuenta(models.Model):
     def __str__(self):
         return f"{self.nombre} ({self.tipo})"
 
+
 class Movimiento(models.Model):
     usuario = models.ForeignKey(ReyMotaUser, on_delete=models.CASCADE)
     cuenta_origen = models.ForeignKey(Cuenta, on_delete=models.CASCADE, related_name='movimientos_salida', default=1)
@@ -26,6 +28,7 @@ class Movimiento(models.Model):
     def __str__(self):
         return f"{self.cuenta_origen.nombre} → {self.cuenta_destino.nombre} - {self.monto} ({self.fecha})"
 
+
 class MovimientoFrecuente(models.Model):
     nombre = models.CharField(max_length=100)
     usuario = models.ForeignKey(ReyMotaUser, on_delete=models.CASCADE)

+ 0 - 0
finanzas/tests.py → src/finanzas/tests.py


+ 0 - 2
finanzas/urls.py → src/finanzas/urls.py

@@ -14,5 +14,3 @@ urlpatterns = [
     path('cuentas/<int:cuenta_id>/editar/', views.editar_cuenta, name='editar_cuenta'),
     path('cuentas/<int:cuenta_id>/eliminar/', views.eliminar_cuenta, name='eliminar_cuenta'),
 ]
-
-

+ 11 - 17
finanzas/views.py → src/finanzas/views.py

@@ -1,4 +1,4 @@
-from django.shortcuts import render, redirect,  get_object_or_404
+from django.shortcuts import render, redirect, get_object_or_404
 from decimal import Decimal, InvalidOperation
 import logging
 import re
@@ -13,11 +13,12 @@ from django.utils.timezone import now
 
 logger = logging.getLogger(__name__)
 
+
 @login_required
 def dashboard(request):
-        # Copiamos GET para poder modificarlo
+    # Copiamos GET para poder modificarlo
     request.GET = request.GET.copy()
-    
+
     # Si se solicitó limpiar la búsqueda, la eliminamos de los datos
     if 'limpiar_busqueda' in request.GET:
         request.GET['buscar'] = ''
@@ -29,21 +30,12 @@ def dashboard(request):
     frecuentes = MovimientoFrecuente.objects.filter(usuario=request.user)
 
     form_filtro = FiltroForm(request.GET or None)
-    
+
     if form_filtro.is_valid():
-#        if form.cleaned_data['fecha_inicio']:
-#            movimientos = movimientos.filter(fecha__gte=form.cleaned_data['fecha_inicio'])
-#        if form.cleaned_data['fecha_fin']:
-#            movimientos = movimientos.filter(fecha__lte=form.cleaned_data['fecha_fin'])
-#        if form.cleaned_data['cuenta']:
-#            cuenta = form.cleaned_data['cuenta']
-#            movimientos = movimientos.filter(models.Q(cuenta_origen=cuenta) | models.Q(cuenta_destino=cuenta))
         busqueda = form_filtro.cleaned_data.get('buscar')
         if busqueda:
             movimientos = movimientos.filter(
-                db_models.Q(descripcion__icontains=busqueda) |
-                db_models.Q(cuenta_origen__nombre__icontains=busqueda) |
-                db_models.Q(cuenta_destino__nombre__icontains=busqueda)
+                db_models.Q(descripcion__icontains=busqueda) | db_models.Q(cuenta_origen__nombre__icontains=busqueda) | db_models.Q(cuenta_destino__nombre__icontains=busqueda)
             )
 
 #    logger.warning(f"Frecuentes: {frecuentes}")
@@ -59,6 +51,7 @@ def dashboard(request):
 
 # Movimientos
 
+
 @login_required
 def agregar_movimiento(request):
     if request.method == 'POST':
@@ -197,6 +190,7 @@ def duplicar_movimiento(request, movimiento_id):
 
 # Cuentas
 
+
 @login_required
 def agregar_cuenta(request):
     if request.method == 'POST':
@@ -220,11 +214,11 @@ def listar_cuentas(request):
         busqueda = form_filtro.cleaned_data.get('buscar')
         if busqueda:
             cuentas = cuentas.filter(
-                db_models.Q(nombre__icontains=busqueda) 
+                db_models.Q(nombre__icontains=busqueda)
             )
 
-    return render(request, 'listar_cuentas.html', 
-                  {'cuentas': cuentas ,'form_filtro': form_filtro})
+    return render(request, 'listar_cuentas.html',
+                  {'cuentas': cuentas, 'form_filtro': form_filtro})
 
 
 @login_required

+ 0 - 0
manage.py → src/manage.py


+ 0 - 0
misfinanzas/__init__.py → src/misfinanzas/__init__.py


+ 0 - 0
misfinanzas/asgi.py → src/misfinanzas/asgi.py


+ 13 - 0
src/misfinanzas/context_processors.py

@@ -0,0 +1,13 @@
+from django.conf import settings
+
+
+def app_version(request):
+    return {
+        'APP_VERSION': settings.APP_VERSION
+    }
+
+
+def isopenshift(request):
+    return {
+        'OPENSHIFT': settings.OPENSHIFT
+    }

+ 87 - 7
misfinanzas/settings.py → src/misfinanzas/settings.py

@@ -12,6 +12,13 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
 
 import os
 from pathlib import Path
+import logging
+
+
+APP_NAME = "Finanzas"
+APP_VERSION = os.environ.get("APP_VERSION", "0.0.0-dev")  # Valor por defecto si no está definido
+IMG_VERSION = os.environ.get("IMG_VERSION", "0.0.0-dev")  # Valor por defecto si no está definido
+
 
 # Build paths inside the project like this: BASE_DIR / 'subdir'.
 BASE_DIR = Path(__file__).resolve().parent.parent
@@ -25,8 +32,9 @@ SECRET_KEY = 'django-insecure-^9*3@g$5brgjmhv&h!h*)c9kp)8i5tnqee_eu+fi728@g96#8&
 
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = True
+OPENSHIFT = os.environ["OPENSHIFT"] == 'True'
 
-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = [".ocp-cluster.reymota.lab", ".reymota.es", ".reymota.lab"]
 
 
 # Application definition
@@ -38,8 +46,11 @@ INSTALLED_APPS = [
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
+
     'finanzas',
     'reymotausers',
+
+    'rest_framework',
 ]
 
 MIDDLEWARE = [
@@ -64,7 +75,11 @@ TEMPLATES = [
                 'django.template.context_processors.request',
                 'django.contrib.auth.context_processors.auth',
                 'django.contrib.messages.context_processors.messages',
+                'misfinanzas.context_processors.app_version',
             ],
+            'libraries': {
+                'filtros_de_entorno': 'misfinanzas.templatetags.filtros_de_entorno',
+            }
         },
     },
 ]
@@ -77,8 +92,12 @@ WSGI_APPLICATION = 'misfinanzas.wsgi.application'
 
 DATABASES = {
     'default': {
-        'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': BASE_DIR / 'db.sqlite3',
+        "ENGINE": "django.db.backends.postgresql",
+        "NAME": "finanzas",
+        "USER": "creylopez",
+        "PASSWORD": "Dsa-0213",
+        "HOST": "postgresql",
+        "PORT": "5432",
     }
 }
 
@@ -107,11 +126,15 @@ AUTH_PASSWORD_VALIDATORS = [
 
 LANGUAGE_CODE = 'es-es'
 
-TIME_ZONE = 'UTC'
+TIME_ZONE = 'Europe/Madrid'
 
 USE_I18N = True
 
 USE_TZ = True
+I18N = True
+L10N = True
+DECIMAL_SEPARATOR = ','
+THOUSAND_SEPARATOR = '.'
 
 
 # Static files (CSS, JavaScript, Images)
@@ -119,9 +142,12 @@ USE_TZ = True
 
 STATIC_URL = 'static/'
 STATIC_ROOT = BASE_DIR / "staticfiles"
-STATICFILES_DIRS = [
-    BASE_DIR / "static",
-]   
+STATICFILES_DIRS = [BASE_DIR / "static",]
+
+# Mediafiles
+
+MEDIA_ROOT = BASE_DIR / "mediafiles"
+MEDIA_URL = '/media/'
 
 # Default primary key field type
 # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
@@ -135,3 +161,57 @@ LOGOUT_REDIRECT_URL = 'dashboard'
 AUTH_USER_MODEL = "reymotausers.ReyMotaUser"
 
 CSRF_TRUSTED_ORIGINS = ["https://*.ocp-cluster.reymota.lab", "https://*.reymota.es", "http://*.rancher.reymota.lab"]
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': False,
+    'formatters': {
+        'verbose': {
+            'format': '{levelname} {asctime} {module} {message}',
+            'style': '{',
+        },
+        'simple': {
+            'format': '{levelname} {message}',
+            'style': '{',
+        },
+    },
+    'handlers': {
+        'console': {
+            'level': 'DEBUG',
+            'class': 'logging.StreamHandler',
+            'formatter': 'simple',
+        },
+        'file': {
+            'level': 'DEBUG',
+            'class': 'logging.FileHandler',
+            'filename': '/dev/null',
+            'formatter': 'verbose',
+        },
+        'mail_admins': {
+            'level': 'ERROR',
+            'class': 'django.utils.log.AdminEmailHandler',
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['file'],
+            'level': 'DEBUG',
+            'propagate': True,
+        },
+        'repostajes': {
+            'handlers': ['console', 'file'],
+            'level': 'DEBUG',
+            'propagate': False,
+        },
+        'lyrics': {
+            'handlers': ['console', 'file'],
+            'level': 'DEBUG',
+            'propagate': False,
+        },
+        'django.request': {
+            'handlers': ['mail_admins'],
+            'level': 'ERROR',
+            'propagate': False,
+        },
+    },
+}

+ 0 - 0
reymotausers/__init__.py → src/misfinanzas/templatetags/__init__.py


+ 9 - 0
src/misfinanzas/templatetags/filtros_de_entorno.py

@@ -0,0 +1,9 @@
+import os
+from django import template
+
+register = template.Library()
+
+
+@register.filter
+def muestra_version(clave):
+    return os.getenv(clave, '')

+ 3 - 3
misfinanzas/urls.py → src/misfinanzas/urls.py

@@ -22,8 +22,8 @@ from django.conf.urls.static import static
 urlpatterns = [
     path('marcelo/', admin.site.urls),
 
-    path("accounts/", include("accounts.urls")),  # new     
+    path("accounts/", include("accounts.urls")),  # new
     path("accounts/", include("django.contrib.auth.urls")),
-    
+
     path('', include('finanzas.urls')),
-]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

+ 40 - 0
src/misfinanzas/views.py

@@ -0,0 +1,40 @@
+import os
+from django.conf import settings
+from django.contrib.auth.decorators import user_passes_test
+from django.shortcuts import render
+from django.http import HttpResponseForbidden
+
+
+@user_passes_test(lambda u: u.is_staff)
+def ver_variables_entorno(request):
+    if not settings.DEBUG:
+        return HttpResponseForbidden("Acceso prohibido")
+
+    # Variables a excluir por motivos de seguridad
+    variables_excluidas = {'SECRET_KEY', 'DATABASES', 'EMAIL_HOST_PASSWORD', 'API_KEY'}
+
+    # Obtiene todas las variables de entorno
+    entorno = {key: os.getenv(key) for key in os.environ.keys() if key not in variables_excluidas}
+
+    # Obtiene todas las variables de settings excluyendo las confidenciales
+    configuracion = {
+        key: getattr(settings, key) for key in dir(settings)
+        if key.isupper() and key not in variables_excluidas
+    }
+
+    # Combina ambas en un solo diccionario
+    contexto = {
+        'entorno': entorno,
+        'configuracion': configuracion
+    }
+
+    return render(request, 'ver_entorno.html', contexto)
+
+
+def acerca_de(request):
+    context = {
+        "app_name": settings.APP_NAME,
+        "app_version": settings.APP_VERSION,
+        "img_version": settings.IMG_VERSION
+    }
+    return render(request, "acerca_de.html", context)

+ 0 - 0
misfinanzas/wsgi.py → src/misfinanzas/wsgi.py


+ 0 - 0
profile_images/Imagen_generada.jpeg → src/profile_images/Imagen_generada.jpeg


+ 0 - 0
profile_images/Imagen_generada_jZWkGR5.jpeg → src/profile_images/Imagen_generada_jZWkGR5.jpeg


+ 0 - 0
profile_images/default.jpg → src/profile_images/default.jpg


+ 20 - 0
src/requirements.txt

@@ -0,0 +1,20 @@
+asgiref==3.8.1
+Django==4.2
+django-calculation==1.0.0
+djangorestframework==3.15.2
+flake8==7.1.1
+gunicorn==22.0.0
+mccabe==0.7.0
+numpy==2.2.2
+packaging==24.1
+pandas==2.2.3
+pillow==10.4.0
+psycopg2-binary==2.9.6
+pycodestyle==2.12.1
+pyflakes==3.2.0
+python-dateutil==2.9.0.post0
+pytz==2025.1
+six==1.17.0
+sqlparse==0.5.1
+typing_extensions==4.12.2
+tzdata==2025.1

+ 0 - 0
reymotausers/management/__init__.py → src/reymotausers/__init__.py


+ 0 - 0
reymotausers/admin.py → src/reymotausers/admin.py


+ 0 - 0
reymotausers/apps.py → src/reymotausers/apps.py


+ 0 - 0
reymotausers/forms.py → src/reymotausers/forms.py


+ 0 - 0
reymotausers/management/commands/__init__.py → src/reymotausers/management/__init__.py


+ 0 - 0
reymotausers/migrations/__init__.py → src/reymotausers/management/commands/__init__.py


+ 0 - 0
reymotausers/management/commands/importar_usuarios.py → src/reymotausers/management/commands/importar_usuarios.py


+ 0 - 0
reymotausers/managers.py → src/reymotausers/managers.py


+ 0 - 0
reymotausers/migrations/0001_initial.py → src/reymotausers/migrations/0001_initial.py


+ 0 - 0
src/reymotausers/migrations/__init__.py


+ 0 - 0
reymotausers/models.py → src/reymotausers/models.py


+ 0 - 0
reymotausers/serializers.py → src/reymotausers/serializers.py


+ 0 - 0
reymotausers/tests.py → src/reymotausers/tests.py


+ 0 - 0
reymotausers/urls.py → src/reymotausers/urls.py


+ 0 - 0
reymotausers/views.py → src/reymotausers/views.py


+ 0 - 0
static/bootstrap/css/bootstrap-icons.css → src/static/bootstrap/css/bootstrap-icons.css


+ 0 - 0
static/bootstrap/css/bootstrap.min.css → src/static/bootstrap/css/bootstrap.min.css


+ 0 - 0
static/bootstrap/css/bootstrap.min.css.map → src/static/bootstrap/css/bootstrap.min.css.map


+ 0 - 0
static/bootstrap/css/fonts/bootstrap-icons.woff → src/static/bootstrap/css/fonts/bootstrap-icons.woff


+ 0 - 0
static/bootstrap/css/fonts/bootstrap-icons.woff2 → src/static/bootstrap/css/fonts/bootstrap-icons.woff2


Некоторые файлы не были показаны из-за большого количества измененных файлов