from smtplib import SMTPException import collections from xhtml2pdf import pisa from django.views.generic.edit import CreateView from django.views import View from django.urls import reverse from django.http import HttpResponse, HttpResponseRedirect from django.core.mail import send_mail, BadHeaderError from django.template.loader import get_template, render_to_string from formtools.wizard.views import CookieWizardView from django.shortcuts import render from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.utils.translation import gettext_lazy as _ from .models import Employee, DEPARTMENT_CHOICES, OS_CHOICES, \ LANG_CHOICES, HARDWARE_CHOICES, TRANSPONDER_CHOICES, KEYBOARD_CHOICES, JANEIN_CHOICES from .forms import PersonalForm, HRForm, ITForm, RestForm, DummyForm, TYPE_CHOICES from .settings import MAILS, EVA_MAIL, BASIC_DATA, ONLY_ONBOARDING def success(request): return HttpResponse(f"Vielen Dank! Du hast E.V.A. erfolgreich ausgefüllt. Die Mails an die Abteilungen wurden versendet. Kopien gehen an {request.user.email}.") def long_process(wizard): '''this method is called via urls.py to determine if a form is part of the IN-Process''' if ONLY_ONBOARDING: wizard.set_choice('IN') return True else: data = wizard.get_cleaned_data_for_step('0') or {} # print(data) if data.get('choice') != 'CHANGE': wizard.set_choice('IN') # print('PROZESS IN') return True else: wizard.set_choice('CHANGE') # print('PROZESS NOT IN') return False def change_process(wizard): ''' this method is called via urls.py to determine if the form is part of the change process''' # print('CHANGE PROZESS') return not long_process(wizard) def beautify_data_pdf(data): # Function for displaying the form items in correct order for handover pdf hardware = data.get('hardware', []) choices_dict = dict(ITForm.base_fields['hardware'].choices) selected_hardware = [choices_dict[val] for val in hardware] return { 'firstname': data.get('firstname', ''), 'lastname': data.get('lastname', ''), 'laptop_id': data.get('laptop_id', ''), 'hardware': selected_hardware, 'mobile': data.get('mobile', ''), 'credit_card': data.get('credit_card', ''), 'sim': data.get('sim', ''), 'transponder_id': data.get('transponder_id', ''), 'pension': data.get('pension', ''), 'miscellaneous': data.get('miscellaneous', ''), 'bahncard': data.get('bahncard', ''), } class EvaFormView(LoginRequiredMixin, CookieWizardView): template_name = 'austritt/employee_form.html' form_list = [PersonalForm, HRForm, ITForm, RestForm, DummyForm, DummyForm, DummyForm] instance = None choice = 'IN' # maybe we dont need this, if *_process() would be class methods, # but unsure if this would work fine with the entries in urls.py def set_choice(self, c): self.choice = c def generate_email(self, data): (first, *_) = data['firstname'].split(maxsplit=1) (last, *_) = data['lastname'].split(maxsplit=1) name = first + '.' + last #if not data['intern']: # mail = name + '_ext@wikimedia.de' #else: mail = name + '@wikimedia.de' data['email'] = mail def get_all_cleaned_data(self): '''this method deletes data which is only used temporary and is not in the modell, it also changes the mail adress of the employee in some circumstances''' data = super().get_all_cleaned_data() self.generate_email(data) # print("delete CHOICE FROM DATA") if 'choice' in data: del data['choice'] return data def get_context_data(self, form, **kwargs): '''this method is called to give context data to the template''' #print('GETCONTEXT') context = super().get_context_data(form=form, **kwargs) testmode = settings.DEBUG or settings.MAILTEST context.update({'choice': self.choice, 'choice_string': TYPE_CHOICES[self.choice], 'TESTMODE': testmode}) # six steps for testing purposes ONLY!! # deliver context for forms if we are in the last step if (self.steps.step1 == 6 or (self.choice != 'IN' and self.steps.step1 == 6)): context.update({'data': self.beautify_data(self.get_all_cleaned_data()), 'datatable': 1,}) if (self.steps.step1 == 5): pdf_data = beautify_data_pdf(self.get_all_cleaned_data()) # storing for PDF class self.request.session['pdf_data'] = pdf_data self.request.session.modified = True #forcing session saving context.update({'pdf_data': pdf_data,}) return context def get_form_instance(self,step): ''' this method assures, that we use the same model instance for all steps''' if self.instance == None: self.instance = Employee() return self.instance def done(self, form_list, **kwargs): '''this method is called from CookieWizardView after all forms are filled''' print ('INSTANCE_DICT') print(self.instance_dict) # save data to database for form in form_list: form.save() # send data to departments for dep in MAILS: response = self.send_mail_to_department(dep) if not settings.DEBUG: self.instance.delete() if response: return response else: return HttpResponseRedirect('success') def send_mail_to_department(self, department): 'send a mail to the given department with the nececcary notifications' print(f'send mail to department {department}...') contact = self.request.user.email data = self.get_all_cleaned_data() # some data should be in every mail newdata = {k: v for k, v in data.items() if (k in BASIC_DATA)} # only the relevant data should be in the context newdata.update({k: v for k, v in data.items() if (k in MAILS[department]['DATA'])}) context = {'data': self.beautify_data(newdata), 'contact': contact} firstname = data['firstname'] lastname = data['lastname'] lastday = data['lastdate_employment'] try: mail_template = get_template(f'austritt/department_mail.txt') if settings.MAILTEST: send_mail( f'EVA: Austritt {firstname} {lastname} {lastday} (MAILTEST)', mail_template.render(context), EVA_MAIL, [EVA_MAIL], fail_silently=False) elif department != "SUBMITTER": send_mail( f'EVA: Austritt {firstname} {lastname} {lastday}', mail_template.render(context), EVA_MAIL, [MAILS[department]['MAIL']], fail_silently=False) else: send_mail( f'EVA: Austritt {firstname} {lastname} {lastday}', mail_template.render(context), EVA_MAIL, [contact], fail_silently=False) except BadHeaderError as error: print(error) self.instance.delete() return HttpResponse(f'{error}

Invalid header found. Data not saved!') except SMTPException as error: print(error) self.instance.delete() return HttpResponse(f'{error}

Error in sending mails (probably wrong adress?). Data not saved!') except Exception as error: print(error) # self.instance.delete() return HttpResponse(f'{error}

Error in sending mails. Data not saved! Please contact ' + EVA_MAIL) return False def beautify_data(self, data): ''' # use long form for contextdata instead of short form if available # # ATTENTION! # This implementation works only for unique keys over all of these dicts from model.py # ''' # update values in data dictionary with keys from *_CHOICES if present there choices = {**DEPARTMENT_CHOICES, **TRANSPONDER_CHOICES, **OS_CHOICES, **LANG_CHOICES, **KEYBOARD_CHOICES} data.update({k:choices[v] for k,v in data.items() \ if isinstance(v,collections.abc.Hashable) \ and v in choices}) # replace values in accounts array from *_CHOICES if 'accounts' in data: data['accounts'] = [ACCOUNT_CHOICES[c] for c in data['accounts']] # replace keys in data dictionary with verbose_name # a bit ugly workaround here: we need to store 'email' away, because it es not in the modell mail = '' if 'email' in data: mail = data.pop('email') newdata = {self.instance._meta.get_field(k).verbose_name.title() : v for k,v in data.items()} if mail: newdata['Email'] = mail # translate booleans newdata.update({k:'Ja' for k,v in newdata.items() if isinstance(v,bool) and v == True}) newdata.update({k:'Nein' for k,v in newdata.items() if isinstance(v,bool) and v == False}) # handle some special data types newdata.update({k:'' for k,v in newdata.items() if v == None}) newdata.update({k:'' for k,v in newdata.items() if v == []}) return newdata # Class for rendering PDf class PDFPreviewView(LoginRequiredMixin, View): def get(self, request): pdf_data=request.session.get('pdf_data') #getting names for pdf file naming firstname = pdf_data.get('firstname') lastname = pdf_data.get('lastname') #hardcoded imagepath => change for production!!! context ={ 'pdf_data': pdf_data, 'image_path': '/home/marike.vossbeck/eva/austritt/static/evapp/logo.png' } html_string =render_to_string('austritt/pdf_template.html', context) response = HttpResponse(content_type='application/pdf') response['Content-Disposition']=f'inline; filename="Rueckgabe_Arbeitsmittel_{firstname}_{lastname}.pdf"' pisa.CreatePDF(html_string, dest=response) return response