Procházet zdrojové kódy

Frequencias de reportes fijas, logging a archivo y consola

Tomás Ponce Gessi před 3 roky
rodič
revize
face6e03b7
6 změnil soubory, kde provedl 62 přidání a 22 odebrání
  1. 15 1
      app/api/config.py
  2. 9 14
      app/api/models.py
  3. 3 1
      app/api/tasks.py
  4. 2 6
      app/api/validators.py
  5. 32 0
      app/preports/settings.py
  6. 1 0
      docker-compose.yml

+ 15 - 1
app/api/config.py

@@ -1,10 +1,24 @@
+from datetime import datetime
 from dateutil.relativedelta import relativedelta as reldelta
 from dateutil.relativedelta import relativedelta as reldelta
 from django.utils.timezone import timedelta as delta
 from django.utils.timezone import timedelta as delta
 
 
 CALENDAR_FREQUENCIES = {
 CALENDAR_FREQUENCIES = {
     "daily": delta(days=1),
     "daily": delta(days=1),
     "weekly": reldelta(weeks=1),
     "weekly": reldelta(weeks=1),
-    "biweekly": reldelta(weeks=2),
     "monthly": reldelta(months=1),
     "monthly": reldelta(months=1),
     "yearly": reldelta(years=1)
     "yearly": reldelta(years=1)
 }
 }
+
+def get_next_calendar_date(date: datetime, frequency: str):
+    base_date: datetime = date.replace(hour=3, minute=0, second=0, microsecond=0)
+    if frequency == "daily":
+        return base_date + delta(days=1)
+    if frequency == "weekly":
+        days_ahead = -date.weekday() + 7 # Lunes
+        return base_date + delta(days=days_ahead)
+    if frequency == "monthly":
+        return (base_date.replace(day=1) + reldelta(months=1))
+    if frequency == "yearly":
+        return (base_date.replace(day=1, month=1) + reldelta(years=1))
+    return None
+

+ 9 - 14
app/api/models.py

@@ -1,9 +1,12 @@
-from datetime import date, timedelta
 from django.db import models
 from django.db import models
 from .validators import json_email_array, json_not_empty_string_array, valid_frequency_format
 from .validators import json_email_array, json_not_empty_string_array, valid_frequency_format
 from django.utils import timezone
 from django.utils import timezone
+from api.config import CALENDAR_FREQUENCIES, get_next_calendar_date
 from django.conf import settings
 from django.conf import settings
-from api.config import CALENDAR_FREQUENCIES
+import requests
+import logging
+logger = logging.getLogger('django')
+
 
 
 class ProgrammedReport(models.Model):
 class ProgrammedReport(models.Model):
     REPORT_FORMATS = [
     REPORT_FORMATS = [
@@ -13,7 +16,7 @@ class ProgrammedReport(models.Model):
 
 
     name = models.CharField(max_length=100)
     name = models.CharField(max_length=100)
     user_id = models.CharField(max_length=2048)
     user_id = models.CharField(max_length=2048)
-    frequency = models.CharField(max_length=20, default="Mensual", validators=[valid_frequency_format])
+    frequency = models.CharField(max_length=20, default="monthly", validators=[valid_frequency_format])
     start_report_date = models.DateTimeField(
     start_report_date = models.DateTimeField(
         default=timezone.now)
         default=timezone.now)
     last_report_date = models.DateTimeField(
     last_report_date = models.DateTimeField(
@@ -37,15 +40,12 @@ class ProgrammedReport(models.Model):
     # Actualiza la due_date en cada save del modelo.
     # Actualiza la due_date en cada save del modelo.
     def save(self, *args, **kwargs):
     def save(self, *args, **kwargs):
         base_date = self.last_report_date if self.last_report_date is not None else self.start_report_date
         base_date = self.last_report_date if self.last_report_date is not None else self.start_report_date
-        self.due_date = base_date + self.timestamp_freq
+        self.due_date = get_next_calendar_date(base_date, self.frequency)
         super().save(*args, **kwargs)
         super().save(*args, **kwargs)
 
 
 
 
     # Metodo que envía la petición a Clima para enviar el reporte.
     # Metodo que envía la petición a Clima para enviar el reporte.
     def send_report(self):
     def send_report(self):
-        import requests
-        from django.conf import settings
-
         # Calculamos el formato en el que Clima requiere recibir los rangos.
         # Calculamos el formato en el que Clima requiere recibir los rangos.
         start_date = (self.last_report_date if self.last_report_date is not None else self.start_report_date).strftime(
         start_date = (self.last_report_date if self.last_report_date is not None else self.start_report_date).strftime(
             "%d/%m/%Y %H:%M")
             "%d/%m/%Y %H:%M")
@@ -65,8 +65,7 @@ class ProgrammedReport(models.Model):
         }, headers={"AUTHORIZATION": settings.PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN})
         }, headers={"AUTHORIZATION": settings.PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN})
 
 
         if response.status_code != 200:
         if response.status_code != 200:
-            import logging
-            logging.getLogger('django').error(
+            logger.critical(
                 "No se pudo enviar el reporte asincrono: %s\n Reason: %s", self, response.reason)
                 "No se pudo enviar el reporte asincrono: %s\n Reason: %s", self, response.reason)
             # TODO! Seria ideal enviar un email al administrador para ver que paso.
             # TODO! Seria ideal enviar un email al administrador para ver que paso.
             return False
             return False
@@ -76,9 +75,6 @@ class ProgrammedReport(models.Model):
         return True
         return True
 
 
     def send_report_now(self):
     def send_report_now(self):
-        import requests
-        from django.conf import settings
-
         # Calculamos el formato en el que Clima requiere recibir los rangos.
         # Calculamos el formato en el que Clima requiere recibir los rangos.
         end_date = timezone.datetime.now()
         end_date = timezone.datetime.now()
         start_date = end_date - self.timestamp_freq
         start_date = end_date - self.timestamp_freq
@@ -100,8 +96,7 @@ class ProgrammedReport(models.Model):
         }, headers={"AUTHORIZATION": settings.PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN})
         }, headers={"AUTHORIZATION": settings.PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN})
 
 
         if response.status_code != 200:
         if response.status_code != 200:
-            import logging
-            logging.getLogger('django').error(
+            logger.critical(
                 "No se pudo enviar el reporte asincrono: %s\n Reason: %s", self, response.reason)
                 "No se pudo enviar el reporte asincrono: %s\n Reason: %s", self, response.reason)
             # TODO! Seria ideal enviar un email al administrador para ver que paso.
             # TODO! Seria ideal enviar un email al administrador para ver que paso.
             return False
             return False

+ 3 - 1
app/api/tasks.py

@@ -1,5 +1,7 @@
 from .models import ProgrammedReport
 from .models import ProgrammedReport
 from django.utils import timezone
 from django.utils import timezone
+import logging
+logger = logging.getLogger('django')
 
 
 # Task que determina que reportes deben ser enviados:
 # Task que determina que reportes deben ser enviados:
 # Ejecutado por Cron (Ver settings.py)
 # Ejecutado por Cron (Ver settings.py)
@@ -8,4 +10,4 @@ def send_programmed_reports_task():
     for preport in ProgrammedReport.objects.all():        
     for preport in ProgrammedReport.objects.all():        
         if timenow > preport.due_date:
         if timenow > preport.due_date:
             sent = preport.send_report()
             sent = preport.send_report()
-            print("Se envio" if sent else "No se pudo enviar","el Programmed Report ID:", preport.id)
+            logger.info("Se envio" if sent else "No se pudo enviar","el Programmed Report ID:", preport.id)

+ 2 - 6
app/api/validators.py

@@ -7,15 +7,11 @@ from api.config import CALENDAR_FREQUENCIES
 
 
 def valid_frequency_format(freq: String):
 def valid_frequency_format(freq: String):
     '''
     '''
-    Ve que el valor sea alguna de las frequencias calendario definidad en CALENDAR_FREQUENCIES o que sea
-    un valor entero.
+    Ve que el valor sea alguna de las frequencias calendario definidad en CALENDAR_FREQUENCIES
     '''
     '''
 
 
     if freq not in CALENDAR_FREQUENCIES:
     if freq not in CALENDAR_FREQUENCIES:
-        if not freq.isdigit():
-            raise ValidationError("Debe ser una frequencia calendario o un entero positivo.")
-        if int(freq) <= 0:
-            raise ValidationError("Debe ser un entero positivo")
+        raise ValidationError("Debe ser una frequencia calendario.")
 
 
 def json_email_array(val: List):
 def json_email_array(val: List):
     '''
     '''

+ 32 - 0
app/preports/settings.py

@@ -145,3 +145,35 @@ CRONJOBS = [
 ]
 ]
 
 
 PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN = os.getenv("PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN")
 PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN = os.getenv("PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN")
+
+LOGGING = {
+    "version": 1,
+    "disable_existing_loggers": False,
+    "formatters": {
+        "verbose": {
+            "format": "%(lineno)d: %(levelname)s %(asctime)s %(module)s %(message)s"
+        },
+        "simple": {"format": "%(asctime)s: %(message)s"},
+    },
+    "handlers": {
+        "django-log-file": {
+            "level": "WARNING",
+            "class": "logging.handlers.RotatingFileHandler",
+            "filename": "/logs/django.log",
+            "maxBytes": 1024 * 1024 * 128,  # Files of 128 MB
+            "backupCount": 2,
+            "formatter": "verbose",
+        },
+        "console": {
+            "level": "DEBUG",
+            "class": "logging.StreamHandler",
+            "formatter": "verbose",
+        },
+    },
+    "loggers": {
+        "django": {
+            "handlers": ["django-log-file", "console"],
+            "propagate": True,
+        },
+    },
+}

+ 1 - 0
docker-compose.yml

@@ -15,6 +15,7 @@ services:
       - "8080:8000"
       - "8080:8000"
     volumes:
     volumes:
       - ./app:/app
       - ./app:/app
+      - ./logs:/logs
   preports-db:
   preports-db:
     image: postgres
     image: postgres
     env_file: ./.env.dev
     env_file: ./.env.dev