diff --git a/cntmanage/cntmanage/settings.py b/cntmanage/cntmanage/settings.py index ee47d6b..82efb31 100644 --- a/cntmanage/cntmanage/settings.py +++ b/cntmanage/cntmanage/settings.py @@ -154,4 +154,4 @@ EMAIL_PORT = 587 EMAIL_USE_TLS = True EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" -EMAIL_FILE_PATH = "/tmp/app-messages" # change this to a proper location +EMAIL_FILE_PATH = "/mnt/d/Test/flightslot-mail" # change this to a proper location diff --git a/cntmanage/cntmanage/settings_prod.py b/cntmanage/cntmanage/settings_prod.py index 686b723..50d50cc 100644 --- a/cntmanage/cntmanage/settings_prod.py +++ b/cntmanage/cntmanage/settings_prod.py @@ -75,7 +75,7 @@ ROOT_URLCONF = 'cntmanage.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': ['/var/www/templates'], + 'DIRS': ['/var/www/templates', '/app/templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -139,6 +139,9 @@ USE_TZ = True # https://docs.djangoproject.com/en/5.1/howto/static-files/ STATIC_URL = "static/" STATIC_ROOT = "/var/www/static/" +STATICFILES_DIRS = [ + "/app/static/" +] STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" # Default primary key field type @@ -155,4 +158,4 @@ EMAIL_PORT = 587 EMAIL_USE_TLS = True # Use dummy backed for testing -EMAIL_BACKEND = "django.core.mail.backends..dummy.EmailBackend" +EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" diff --git a/cntmanage/docker/flightslot.Dockerfile b/cntmanage/docker/flightslot.Dockerfile index 7fea967..fb8d0d6 100644 --- a/cntmanage/docker/flightslot.Dockerfile +++ b/cntmanage/docker/flightslot.Dockerfile @@ -19,11 +19,12 @@ FROM python:3.12-slim AS deploy WORKDIR /app # Copy application custom static files RUN mkdir -p static -COPY ./static/cantorair.jpg ./static -COPY ./static/cantorair_blue.jpg ./static +COPY ./static/* ./static # Copy application custom templates for admin page RUN mkdir -p /templates/admin +RUN mkdir -p /templates/email COPY ./templates/admin/* ./templates/admin/ +COPY ./templates/email/* ./templates/email/ # Copy and install application wheel package COPY --from=builder /build/dist/*.whl ./ RUN pip install --no-cache-dir *.whl diff --git a/cntmanage/flightslot/actions/send_email.py b/cntmanage/flightslot/actions/send_email.py index 06a6a35..b5569b9 100644 --- a/cntmanage/flightslot/actions/send_email.py +++ b/cntmanage/flightslot/actions/send_email.py @@ -1,6 +1,6 @@ -from django.conf import settings +from django.contrib.staticfiles import finders from django.contrib import messages -from django.core.mail import EmailMultiAlternatives +from django.core.mail import EmailMultiAlternatives, get_connection from django.http import HttpRequest from django.db.models.query import QuerySet from django.utils.safestring import SafeText @@ -11,24 +11,27 @@ from ..models.students import Student from smtplib import SMTPException from email.mime.image import MIMEImage -import os +from typing import List def send_mail_password(request: HttpRequest, queryset: QuerySet[Student]) -> None: img: MIMEImage | None = None - try: - for d in settings.STATICFILES_DIRS: - filename = os.path.join(d, "cantorair.png") - if not os.path.exists(filename): - continue - with open(filename, "rb") as f: - img = MIMEImage(f.read()) - img.add_header("Content-ID", "logo_image") - img.add_header("Content-Disposition", "inline", filename="cantorair.png") - break - except: + filename: str + candidates = finders.find("cantorair.png") + if not candidates: messages.error(request=request, message="Cannot Load CantorAir Logo") return + elif isinstance(candidates, list): + filename = candidates.pop() + else: + filename = candidates + with open(filename, "rb") as f: + img = MIMEImage(f.read()) + img.add_header("Content-ID", "logo_image") + img.add_header("Content-Disposition", "inline", filename="cantorair.png") + + # build mail list filling template + mails: List[EmailMultiAlternatives] = [] for student in queryset: if not student.user or not student.email: # skip student if has not an associated user continue @@ -52,11 +55,19 @@ def send_mail_password(request: HttpRequest, queryset: QuerySet[Student]) -> Non ) mail.attach(filename=img) mail.attach_alternative(content=html_message, mimetype="text/html") - mail.send() - except SMTPException as e: - messages.error(request=request, message=f"Send Mail error: {e.strerror}") + mails.append(mail) except Exception as e: messages.error(request=request, message=f"General Error: {e}") - else: - messages.success(request=request, message=f"Email Sent To: {student.surname} {student.name[0].upper()}. -> {mail.to.pop()}") - return + + # Open only one conenction and send mass email + try: + with get_connection() as conn: + conn.send_messages(mails) + except SMTPException as e: + messages.error(request=request, message=f"Send Mail SMTP error: {e.strerror}") + except Exception as e: + messages.error(request=request, message=f"Send Mail General error: {e}") + else: + messages.success(request=request, message=f"Successfully sent {len(mails)} messages") + + return \ No newline at end of file diff --git a/cntmanage/flightslot/admins/student_adm.py b/cntmanage/flightslot/admins/student_adm.py index 3cd85f1..0e99952 100644 --- a/cntmanage/flightslot/admins/student_adm.py +++ b/cntmanage/flightslot/admins/student_adm.py @@ -115,9 +115,9 @@ class StudentAdmin(ImportMixin, AdminConfirmMixin, AdminActionFormsMixin, admin. i, ac_types = assign_aircraft(queryset=queryset, data=data) messages.success(request, f"{i} Students updated to {ac_types}") - @admin.action(description="Send Access Credentials e-mail") @confirm_action - def send_mail(self, request: HttpRequest, queryset: QuerySet[Student], data: Any) -> None: + @admin.action(description="Send Access Credentials e-mail") + def send_mail(self, request: HttpRequest, queryset: QuerySet[Student], *args: Any) -> None: send_mail_password(request=request, queryset=queryset) # Return the initial form for import confirmations, request course to user diff --git a/cntmanage/static/password b/cntmanage/static/password deleted file mode 100644 index 520af21..0000000 --- a/cntmanage/static/password +++ /dev/null @@ -1 +0,0 @@ -admin: CantorAir2k25 diff --git a/cntmanage/templates/admin/base_site.html b/cntmanage/templates/admin/base_site.html index d4e9d88..1ed4a89 100644 --- a/cntmanage/templates/admin/base_site.html +++ b/cntmanage/templates/admin/base_site.html @@ -8,8 +8,8 @@

-

diff --git a/note.txt b/note.txt index bc7eaa7..443535e 100644 --- a/note.txt +++ b/note.txt @@ -3,3 +3,6 @@ OK aereo assegnato allo studente di fianco al numero della missione per PPL, inv OK le missioni ripetute su piu' giorni hanno una cella per giorno (non unite) OK lo studente vede solo le missioni della sua fase PPL->PPL ATPL-> tutto OK ogni richiesta ha un colore diverso che cicla con delle tinte pastello + + +password: CantorAir2k25