From 960ec8841c7def51aefc957048e31b61db4bec04 Mon Sep 17 00:00:00 2001 From: alpcentaur Date: Mon, 27 Feb 2023 17:09:29 +0000 Subject: [PATCH] added the automated mail with the possibility to grant travel costs by link in email --- input/forms.py | 8 ++++++- input/management/commands/sendmails.py | 23 ++++++++++++++----- input/migrations/0066_email_adult.py | 18 +++++++++++++++ ..._travel_project_name_alter_library_type.py | 23 +++++++++++++++++++ input/migrations/0068_travel_hotel.py | 18 +++++++++++++++ .../migrations/0069_alter_travel_transport.py | 18 +++++++++++++++ input/migrations/0070_alter_travel_project.py | 19 +++++++++++++++ input/models.py | 14 +++++++++-- input/views.py | 7 +++++- 9 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 input/migrations/0066_email_adult.py create mode 100644 input/migrations/0067_travel_project_name_alter_library_type.py create mode 100644 input/migrations/0068_travel_hotel.py create mode 100644 input/migrations/0069_alter_travel_transport.py create mode 100644 input/migrations/0070_alter_travel_project.py diff --git a/input/forms.py b/input/forms.py index 20b0746..de6fc83 100644 --- a/input/forms.py +++ b/input/forms.py @@ -26,6 +26,7 @@ class ProjectForm(FdbForm): widgets = {'start': AdminDateWidget(), 'end': AdminDateWidget(),} + class ExternForm(FdbForm): choice = ChoiceField(choices=TYPE_CHOICES.items(), widget=RadioSelect, @@ -39,6 +40,7 @@ class ExternForm(FdbForm): model = ConcreteExtern exclude = ('granted', 'granted_date', 'survey_mail_send', 'service_id', 'survey_mail_date') + INTERN_CHOICES = {'PRO': 'Projektsteckbrief', 'HON': 'Ehrenamtsbescheinigung, Akkreditierung oder Redaktionsbestätigung', 'TRAV': 'Reisekostenerstattung'} @@ -51,11 +53,12 @@ class InternForm(FdbForm): model = ConcreteVolunteer exclude = ('granted', 'granted_date', 'survey_mail_send', 'survey_mail_date') + class TravelForm(FdbForm): # TODO: add some javascript to show/hide other-field class Meta: model = Travel - exclude = ('granted', 'granted_date', 'survey_mail_send', 'realname', 'email', 'survey_mail_date') + exclude = ('granted', 'granted_date', 'survey_mail_send', 'realname', 'email', 'survey_mail_date', 'project', 'request_url', 'payed_for_hotel_by', 'payed_for_travel_by' ) widgets = {'checkin': AdminDateWidget(), 'checkout': AdminDateWidget(),} @@ -82,6 +85,7 @@ class CheckForm(FdbForm): label=format_html("Ich stimme den Nutzungsbedingungen zu", NUTZUNGSBEDINGUNGEN)) + class LiteratureForm(CheckForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -115,7 +119,9 @@ class BusinessCardForm(CheckForm): class Media: js = ('dropdown/js/base.js',) + class ListForm(CheckForm): class Meta: model = List fields = ['domain', 'address'] + diff --git a/input/management/commands/sendmails.py b/input/management/commands/sendmails.py index 8471f43..243c396 100644 --- a/input/management/commands/sendmails.py +++ b/input/management/commands/sendmails.py @@ -4,6 +4,7 @@ import sys from django.core.management.base import BaseCommand, CommandError from django.template.loader import get_template from django.core.mail import send_mail, BadHeaderError, EmailMessage +from django.core.mail import EmailMultiAlternatives from django.conf import settings from input.models import Project, Library, HonoraryCertificate, Travel, Email,\ @@ -112,7 +113,8 @@ class Command(BaseCommand): approved_notHappened = Project.objects.filter(status = 'NOT')\ .exclude(end_mail_send = False) - mail_template = get_template('input/if_not_of_project_approved.txt') + html_mail_template = get_template('input/if_not_of_project_approved.html') + txt_mail_template = get_template('input/if_not_of_project_approved.txt') informMail_template = get_template('input/if_end_of_project_orginformed.txt') # send the mail to project.email, which would be the mail of the volunteer that filled out the form @@ -121,11 +123,20 @@ class Command(BaseCommand): context = {'project': project} context['URLPREFIX'] = settings.URLPREFIX try: - send_mail('Projektende erreicht', - mail_template.render(context), - IF_EMAIL, - [project.email], - fail_silently=False) + subject, from_email, to = 'Projektende erreicht', IF_EMAIL, project.email + text_content = txt_mail_template.render(context) + html_content = html_mail_template.render(context) + msg = EmailMultiAlternatives(subject, text_content, from_email, [to]) + msg.attach_alternative(html_content, "text/html") + msg.send() + + + + #send_mail('Projektende erreicht', + # mail_template.render(context), + # IF_EMAIL, + # [project.email], + # fail_silently=False) send_mail('Projektorganisator*in wurde informiert', informMail_template.render(context), IF_EMAIL, diff --git a/input/migrations/0066_email_adult.py b/input/migrations/0066_email_adult.py new file mode 100644 index 0000000..419a9b4 --- /dev/null +++ b/input/migrations/0066_email_adult.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2022-11-17 11:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('input', '0065_alter_literature_selfbuy_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='email', + name='adult', + field=models.CharField(choices=[('TRUE', 'Ich bin volljährig.'), ('FALSE', 'Ich bin noch nicht volljährig.'), ('NONE', 'Nichts ausgewählt')], default='NONE', max_length=10, verbose_name='Volljährigkeit'), + ), + ] diff --git a/input/migrations/0067_travel_project_name_alter_library_type.py b/input/migrations/0067_travel_project_name_alter_library_type.py new file mode 100644 index 0000000..5cbcb7a --- /dev/null +++ b/input/migrations/0067_travel_project_name_alter_library_type.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.2 on 2022-11-17 15:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('input', '0066_email_adult'), + ] + + operations = [ + migrations.AddField( + model_name='travel', + name='project_name', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='Projektname:'), + ), + migrations.AlterField( + model_name='library', + name='type', + field=models.CharField(choices=[('BIB', 'Bibliotheksstipendium'), ('ELIT', 'eLiteraturstipendium'), ('MAIL', 'E-Mail-Adresse'), ('IFG', 'Kostenübernahme IFG-Anfrage'), ('LIT', 'Literaturstipendium'), ('LIST', 'Mailingliste'), ('SOFT', 'Softwarestipendium'), ('VIS', 'Visitenkarten'), ('TRAV', 'Reisekosten')], default='BIB', max_length=4), + ), + ] diff --git a/input/migrations/0068_travel_hotel.py b/input/migrations/0068_travel_hotel.py new file mode 100644 index 0000000..82fd575 --- /dev/null +++ b/input/migrations/0068_travel_hotel.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2022-11-17 15:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('input', '0067_travel_project_name_alter_library_type'), + ] + + operations = [ + migrations.AddField( + model_name='travel', + name='hotel', + field=models.BooleanField(default=False, verbose_name='Hotelzimmer benötigt:'), + ), + ] diff --git a/input/migrations/0069_alter_travel_transport.py b/input/migrations/0069_alter_travel_transport.py new file mode 100644 index 0000000..77538db --- /dev/null +++ b/input/migrations/0069_alter_travel_transport.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2022-11-17 15:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('input', '0068_travel_hotel'), + ] + + operations = [ + migrations.AlterField( + model_name='travel', + name='transport', + field=models.CharField(choices=[('BAHN', 'Bahn'), ('NONE', 'Keine Fahrtkosten'), ('OTHER', 'Sonstiges (mit Begründung)')], default='BAHN', max_length=5, verbose_name='Transportmittel:'), + ), + ] diff --git a/input/migrations/0070_alter_travel_project.py b/input/migrations/0070_alter_travel_project.py new file mode 100644 index 0000000..fe82970 --- /dev/null +++ b/input/migrations/0070_alter_travel_project.py @@ -0,0 +1,19 @@ +# Generated by Django 4.1.2 on 2022-11-17 16:13 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('input', '0069_alter_travel_transport'), + ] + + operations = [ + migrations.AlterField( + model_name='travel', + name='project', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='input.project'), + ), + ] diff --git a/input/models.py b/input/models.py index d1f6589..a92ff61 100644 --- a/input/models.py +++ b/input/models.py @@ -144,14 +144,17 @@ PAYEDBY_CHOICES = {'WMDE': 'WMDE', 'REQU': 'Antragstellender Mensch'} class Travel(Intern): - project = models.ForeignKey(Project, on_delete=models.CASCADE) - transport = models.CharField(max_length=5, choices=TRANSPORT_CHOICES.items(), default='BAHN') + # project variable is now null true and blank true, which means it can be saved without project id to be later on filled out by admins + project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True, blank=True) + project_name = models.CharField(max_length=50, null=True, blank=True, verbose_name='Projektname:') + transport = models.CharField(max_length=5, choices=TRANSPORT_CHOICES.items(), default='BAHN', verbose_name='Transportmittel:') other_transport = models.CharField(max_length=200, null=True, blank=True, verbose_name='Sonstige Transportmittel (mit Begründung)') travelcost = models.CharField(max_length=10, default="0", verbose_name="Fahrtkosten") checkin = models.DateField(blank=True, null=True, verbose_name='Check In') checkout = models.DateField(blank=True, null=True, verbose_name='Check Out') payed_for_hotel_by = models.CharField(max_length=4, choices=PAYEDBY_CHOICES.items(), blank=True, null=True, verbose_name='Kostenauslage Hotel durch') payed_for_travel_by = models.CharField(max_length=4, choices=PAYEDBY_CHOICES.items(), blank=True, null=True, verbose_name='Kostenauslage Fahrt durch') + hotel = models.BooleanField(default=False, verbose_name='Hotelzimmer benötigt:') notes = models.TextField(max_length=1000, blank=True) @@ -174,6 +177,7 @@ TYPE_CHOICES = {'BIB': format_html('Mailingliste'), 'SOFT': format_html('Softwarestipendium'), 'VIS': format_html('Visitenkarten'), + 'TRAV': format_html('Reisekosten'), } # same model is used for Library, ELitStip and Software! @@ -232,6 +236,11 @@ MAIL_CHOICES = {'REALNAME': 'Vorname.Nachname', 'USERNAME': 'Username', 'OTHER': 'Sonstiges:'} +ADULT_CHOICES = {'TRUE': format_html('Ich bin volljährig.'), + 'FALSE': format_html('Ich bin noch nicht volljährig.'), + 'NONE': format_html('Nichts ausgewählt') + } + class Email(Domain): address = models.CharField(max_length=50, choices=MAIL_CHOICES.items(), @@ -239,6 +248,7 @@ class Email(Domain): help_text=format_html("Bitte gib hier den gewünschten Adressbestandteil an,
der sich vor der Domain befinden soll.")) other = models.CharField(max_length=50,blank=True,null=True, verbose_name="Sonstiges") + adult = models.CharField( max_length=10, verbose_name='Volljährigkeit', choices=ADULT_CHOICES.items(), default='NONE') class List(Domain): address = models.CharField(max_length=50, default='NO_ADDRESS', diff --git a/input/views.py b/input/views.py index cadf55a..e86ebbf 100644 --- a/input/views.py +++ b/input/views.py @@ -16,7 +16,7 @@ from django.utils.html import format_html from .forms import ProjectForm, ExternForm, LibraryForm, IFGForm, LiteratureForm,\ HonoraryCertificateForm, InternForm, TravelForm, EmailForm,\ ListForm, BusinessCardForm, INTERN_CHOICES -from .models import Project, TYPE_CHOICES, Library, Literature +from .models import Project, TYPE_CHOICES, Library, Literature, Travel from .settings import IF_EMAIL def auth_deny(choice,pk,auth): @@ -26,6 +26,8 @@ def auth_deny(choice,pk,auth): Literature.set_granted(pk,auth) elif choice == 'IFG': IFG.set_granted(pk,auth) + elif choice == 'TRAV': + Travel.set_granted(pk,auth) else: return HttpResponse(f'ERROR! UNKNOWN CHOICE TYPE! {choice}') return False @@ -134,6 +136,7 @@ LABEL_CHOICES = {'BIB': format_html('Bibliothek'), 'LIST': format_html('Mailingliste'), 'SOFT': format_html('Software'), 'VIS': format_html('Visitenkarten'), + 'TRAV': format_html('Reisekosten'), } HELP_CHOICES = {'BIB': format_html("In welchem Zeitraum möchtest du recherchieren oder
wie lange ist der Bibliotheksausweis gültig?"), @@ -178,6 +181,8 @@ class ExternView(CookieWizardView): elif choice == 'LIST': form = ListForm(data) form.fields['domain'].help_text = format_html("Mit welcher Domain, bzw. für welches Wikimedia-Projekt,
möchtest du eine Mailingliste beantragen?") + elif choice == 'TRAV': + form = TravelForm(data) else: raise RuntimeError(f'ERROR! UNKNOWN FORMTYPE {choice} in ExternView') self.choice = choice