From 54e2f6bdf100d78cb4b2f7f1da91154e248b6840 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Wed, 5 Jul 2023 15:08:18 +0200 Subject: [PATCH] =?UTF-8?q?Commande=20pour=20d=C3=A9tecter=20les=20liens?= =?UTF-8?q?=20cass=C3=A9s=20(#1987)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Simple command to detect Question & Quiz broken links * Send recap email * Add validation_status info * Only send recap email if there are errors --- .../commands/detect_broken_links.py | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 core/management/commands/detect_broken_links.py diff --git a/core/management/commands/detect_broken_links.py b/core/management/commands/detect_broken_links.py new file mode 100644 index 00000000..385853e1 --- /dev/null +++ b/core/management/commands/detect_broken_links.py @@ -0,0 +1,115 @@ +import requests +from django.conf import settings +from django.core.mail import send_mail +from django.core.management import BaseCommand + +from questions.models import Question +from quizs.models import Quiz + + +COMMAND_TITLE = "Commande de détection des liens cassés" + + +QUESTION_URL_FIELDS = Question.QUESTION_URL_FIELDS + Question.QUESTION_IMAGE_URL_FIELDS +QUIZ_URL_FIELDS = Quiz.QUIZ_URL_FIELDS + Quiz.QUIZ_IMAGE_URL_FIELDS +# GLOSSARY_ITEM_URL_FIELDS = GlossaryItem.GLOSSARY_ITEM_URL_FIELDS +# USER_CARD_URL_FIELDS = + + +class Command(BaseCommand): + """ + Usage: + python manage.py detect_broken_links + """ + + def handle(self, *args, **options): + print("=== detect_broken_links running") + + error_list = list() + + question_error_list = self.detect_question_broken_links() + error_list.extend(question_error_list) + quiz_error_list = self.detect_quiz_broken_links() + error_list.extend(quiz_error_list) + + # only send recap email if there are errors + if len(error_list): + self.send_recap_email(error_list) + + def detect_question_broken_links(self): + error_list = list() + progress = 0 + questions = Question.objects.all() + print(f"=== Questions: {questions.count()}") + + for object in questions: + for object_url_field in QUESTION_URL_FIELDS: + url = getattr(object, object_url_field) + if url: + try: + requests.get(url, timeout=10) + except Exception: + error_list.append( + { + "object_type": "Question", + "object_id": object.id, + "object_validation_status": object.validation_status, + "object_field_name": object_url_field, + "object_field_url": url, + } + ) + progress += 1 + if (progress % 100) == 0: + print(f"{progress}...") + + print(f"Questions done. Found {len(error_list)} errors") + return error_list + + def detect_quiz_broken_links(self): + error_list = list() + progress = 0 + quizs = Quiz.objects.all() + print(f"=== Quizs: {quizs.count()}") + + for object in quizs: + for object_url_field in QUIZ_URL_FIELDS: + url = getattr(object, object_url_field) + if url: + try: + requests.get(url, timeout=10) + except Exception: + error_list.append( + { + "object_type": "Quiz", + "object_id": object.id, + "object_validation_status": object.validation_status, + "object_field_name": object_url_field, + "object_field_url": url, + } + ) + progress += 1 + if (progress % 10) == 0: + print(f"{progress}...") + + print(f"Quizs done. Found {len(error_list)} errors") + return error_list + + def send_recap_email(self, error_list): + email_subject = f"[Admin] {COMMAND_TITLE}" + + email_template_html = f"

{COMMAND_TITLE}

" + email_template_html += f"

{len(error_list)} liens cassés

" + email_template_html += "" # noqa + for error in error_list: + email_template_html += f"" # noqa + email_template_html += "
TypeIDStatutNom du champLien cassé
{error['object_type']}{error['object_id']}{error['object_validation_status']}{error['object_field_name']}{error['object_field_url']}
" + + send_mail( + subject=email_subject, + message=email_template_html, + html_message=email_template_html, + from_email=settings.DEFAULT_FROM_EMAIL, + recipient_list=[settings.CONTACT_EMAIL], + fail_silently=False, + ) + print("E-mail recap envoyé")