From 86e61c840b2912448996037b5d04285e83a2f0d8 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Sun, 5 Apr 2020 14:28:00 +0200
Subject: [PATCH] cron job added

---
 smash/web/importer/__init__.py                |  3 +-
 smash/web/importer/importer.py                | 23 ++++++++-
 smash/web/importer/importer_cron_job.py       | 49 +++++++++++++++++++
 smash/web/importer/warning_counter.py         | 15 ++++++
 smash/web/tests/importer/mock_reader.py       |  4 ++
 smash/web/tests/importer/test_importer.py     |  1 +
 .../tests/importer/test_importer_cron_job.py  | 40 +++++++++++++++
 7 files changed, 132 insertions(+), 3 deletions(-)
 create mode 100644 smash/web/importer/importer_cron_job.py
 create mode 100644 smash/web/importer/warning_counter.py
 create mode 100644 smash/web/tests/importer/test_importer_cron_job.py

diff --git a/smash/web/importer/__init__.py b/smash/web/importer/__init__.py
index 76e28e32..785e17b2 100644
--- a/smash/web/importer/__init__.py
+++ b/smash/web/importer/__init__.py
@@ -1,5 +1,6 @@
 from importer import Importer
 from subject_import_reader import SubjectImportReader
 from csv_subject_import_reader import CsvSubjectImportReader
+from importer_cron_job import ImporterCronJob
 
-__all__ = [Importer, SubjectImportReader, CsvSubjectImportReader]
+__all__ = [Importer, SubjectImportReader, CsvSubjectImportReader, ImporterCronJob]
diff --git a/smash/web/importer/importer.py b/smash/web/importer/importer.py
index 2639f670..ab4427fd 100644
--- a/smash/web/importer/importer.py
+++ b/smash/web/importer/importer.py
@@ -4,6 +4,7 @@ import sys
 import traceback
 
 from subject_import_reader import SubjectImportReader
+from warning_counter import MsgCounterHandler
 from web.models import StudySubject, Subject
 from web.models.constants import GLOBAL_STUDY_ID
 
@@ -17,13 +18,21 @@ class Importer(object):
         self.reader = reader
         self.added_count = 0
         self.problematic_count = 0
+        self.merged_count = 0
+        self.warning_count = 0
+        self.study_subjects = []
 
     def execute(self):
         self.added_count = 0
         self.problematic_count = 0
-        study_subjects = self.reader.load_data(self.filename)
+        self.merged_count = 0
+        self.warning_count = 0
 
-        for study_subject in study_subjects:
+        warning_counter = MsgCounterHandler()
+        logging.getLogger('').addHandler(warning_counter)
+
+        self.study_subjects = self.reader.load_data(self.filename)
+        for study_subject in self.study_subjects:
             try:
                 if study_subject.study is None:
                     self.problematic_count += 1
@@ -39,6 +48,9 @@ class Importer(object):
                 self.problematic_count += 1
                 traceback.print_exc(file=sys.stdout)
                 logger.error("Problem with importing study subject: " + study_subject.screening_number)
+        if "WARNING" in warning_counter.level2count:
+            self.warning_count = warning_counter.level2count["WARNING"]
+        logging.getLogger('').removeHandler(warning_counter)
 
     def import_study_subject(self, study_subject):
         # type: (StudySubject) -> None
@@ -51,3 +63,10 @@ class Importer(object):
             study_subject.subject = Subject.objects.filter(id=study_subject.subject.id)[0]
             study_subject.save()
             self.added_count += 1
+
+    def get_summary(self):
+        return "<p>Number of entries: <b>" + str(len(self.study_subjects)) + "</b></p>" + \
+               "<p>Number of successfully added entries: <b>" + str(self.added_count) + "</b></p>" + \
+               "<p>Number of successfully merged entries: <b>" + str(self.merged_count) + "</b></p>" + \
+               "<p>Number of problematic entries: <b>" + str(self.problematic_count) + "</b></p>" + \
+               "<p>Number of raised warnings: <b>" + str(self.warning_count) + "</b></p>"
diff --git a/smash/web/importer/importer_cron_job.py b/smash/web/importer/importer_cron_job.py
new file mode 100644
index 00000000..3a9b0d97
--- /dev/null
+++ b/smash/web/importer/importer_cron_job.py
@@ -0,0 +1,49 @@
+# coding=utf-8
+import logging
+import os.path
+import traceback
+
+import timeout_decorator
+from django.conf import settings
+from django_cron import CronJobBase, Schedule
+
+from csv_subject_import_reader import CsvSubjectImportReader
+from importer import Importer
+from web.models.constants import CRON_JOB_TIMEOUT
+from ..smash_email import EmailSender
+
+logger = logging.getLogger(__name__)
+
+
+class ImporterCronJob(CronJobBase):
+    RUN_EVERY_MINUTES = 60 * 24
+    schedule = Schedule(run_every_mins=RUN_EVERY_MINUTES)
+    code = 'web.import_daily_job'  # a unique code
+
+    @timeout_decorator.timeout(CRON_JOB_TIMEOUT)
+    def do(self):
+        title = "Daily import"
+        recipients = getattr(settings, "DEFAULT_FROM_EMAIL", None)
+
+        filename = getattr(settings, "DAILY_IMPORT_FILE", None)
+        if filename is None:
+            return "import file not defined"
+        if not os.path.isfile(filename):
+            EmailSender().send_email(title,
+                                     "<h1>File with imported data is not available in the system: " + filename + "</h1>",
+                                     recipients)
+        try:
+            importer = Importer(settings.DAILY_IMPORT_FILE, CsvSubjectImportReader())
+            importer.execute()
+            body = importer.get_summary()
+            EmailSender().send_email(title,
+                                     "<h1>Data was successfully imported from file: " + filename + "</h1>" + body,
+                                     recipients)
+            return "import is successful"
+
+        except:
+            tb = traceback.format_exc()
+            EmailSender().send_email(title,
+                                     "<h1>There was a problem with importing data from file: " + filename + "</h1>" + tb,
+                                     recipients)
+            return "import crashed"
diff --git a/smash/web/importer/warning_counter.py b/smash/web/importer/warning_counter.py
new file mode 100644
index 00000000..8500d6a3
--- /dev/null
+++ b/smash/web/importer/warning_counter.py
@@ -0,0 +1,15 @@
+import logging
+
+class MsgCounterHandler(logging.Handler):
+    level2count = None
+
+    def __init__(self, *args, **kwargs):
+        super(MsgCounterHandler, self).__init__(*args, **kwargs)
+        self.level2count = {}
+
+    def emit(self, record):
+        l = record.levelname
+        if l not in self.level2count:
+            self.level2count[l] = 0
+        print(l)
+        self.level2count[l] += 1
diff --git a/smash/web/tests/importer/mock_reader.py b/smash/web/tests/importer/mock_reader.py
index f5435429..a5aedb09 100644
--- a/smash/web/tests/importer/mock_reader.py
+++ b/smash/web/tests/importer/mock_reader.py
@@ -1,5 +1,9 @@
+import logging
+
 from web.importer.subject_import_reader import SubjectImportReader
 
+logger = logging.getLogger(__name__)
+
 
 class MockReader(SubjectImportReader):
     def __init__(self, study_subjects):
diff --git a/smash/web/tests/importer/test_importer.py b/smash/web/tests/importer/test_importer.py
index 320e6bf7..da4bb9c3 100644
--- a/smash/web/tests/importer/test_importer.py
+++ b/smash/web/tests/importer/test_importer.py
@@ -38,6 +38,7 @@ class TestImporter(TestCase):
 
         self.assertEqual(1, importer.added_count)
         self.assertEqual(0, importer.problematic_count)
+        self.assertEqual(0, importer.warning_count)
 
     def test_import_invalid(self):
         study_subjects = []
diff --git a/smash/web/tests/importer/test_importer_cron_job.py b/smash/web/tests/importer/test_importer_cron_job.py
new file mode 100644
index 00000000..f748f902
--- /dev/null
+++ b/smash/web/tests/importer/test_importer_cron_job.py
@@ -0,0 +1,40 @@
+# coding=utf-8
+
+import logging
+
+from django.conf import settings
+from django.test import TestCase
+
+from web.importer import ImporterCronJob
+from web.tests.functions import get_resource_path
+
+logger = logging.getLogger(__name__)
+from django.core import mail
+from django_cron.models import CronJobLog
+
+
+class TestCronJobImporter(TestCase):
+
+    def test_import_without_configuration(self):
+        CronJobLog.objects.all().delete()
+
+        job = ImporterCronJob()
+
+        status = job.do()
+
+        self.assertEqual("import file not defined", status)
+        self.assertEqual(0, len(mail.outbox))
+
+    def test_import(self):
+        filename = get_resource_path('import.csv')
+        setattr(settings, "DAILY_IMPORT_FILE", filename)
+        CronJobLog.objects.all().delete()
+
+        job = ImporterCronJob()
+
+        status = job.do()
+
+        self.assertEqual("import is successful", status)
+        self.assertEqual(1, len(mail.outbox))
+
+        setattr(settings, "DAILY_IMPORT_FILE", None)
-- 
GitLab