from django.shortcuts import render, redirect, reverse from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.contrib.auth.decorators import login_required from django.conf import settings from .usersforms import UsersAddNewUser, UsersAddProfileForm, UsersChangeProfil, AgencyUpdateForm, UsersPermForm, UserAreaTaskForm, SupportForm, NewAgencyForm, NewAgencyFormRD, FormRD from django.views.generic import CreateView, ListView, UpdateView, DetailView, DeleteView, View, TemplateView from django.contrib import messages from django.contrib.auth.models import User, Permission from django.db import models from .models import Profile, Agency, UserTime, UserYearAbsenceInfo, AgencyBills, RegNotfallhilfe from django.core.mail import send_mail from django.http import HttpResponseRedirect,HttpResponse, JsonResponse from areas.models import Areas from tasks.models import Tasks from organizer.models import QuickLinks from .priomodel import Prio from standards.models import Standards from datetime import datetime from django.utils import timezone from django.utils import formats from news.models import News from cloud.models import DataFile import requests import json import random import string from PIL import Image from django.template.loader import render_to_string from django.contrib.auth.forms import PasswordResetForm from django.template.loader import render_to_string from io import StringIO from users.models import AgencyJob, AgencyGroup, AgencyNetwork from django.contrib.auth.models import Group from cloud.models import DataDir from message.models import Message from notificsys.models import UserNotification from organizer.models import AGContacts, AGPassword import sys, os from asgiref.sync import async_to_sync from channels_presence.models import Room from channels_presence.models import Presence import channels.layers from datetime import date, timedelta from timemanagement.models import Workday, Absence, Breaks import base64 import filetype from django.db.models.signals import m2m_changed from django.contrib.auth.models import User, Group from users.signals import adjust_group_notifications_permission from django.core.exceptions import ObjectDoesNotExist from organizer.models import QuickLinks from areas.models import Areas from tasks.models import Tasks ''' ICS ''' from ics import Calendar, Event import base64 from django.contrib.auth import authenticate ''' MAIL ''' from django.core.mail import EmailMessage from django.core.mail import EmailMultiAlternatives import io as BytesIO import base64 from django.http import HttpResponse def getICSFile(request, ag): if 'HTTP_AUTHORIZATION' in request.META: auth = request.META['HTTP_AUTHORIZATION'].split() if len(auth) == 2: if auth[0].lower() == "basic": temp = base64.b64decode(auth[1] + "==") username = temp.decode("utf-8").split(":")[0] passwd = temp.decode("utf-8").split(":")[1] user = authenticate(username=username, password=passwd) if user is not None: if user.is_active: if user.profile.agency.pk == ag: request.user = user c = Calendar() absencedays = Absence.objects.filter(agency=ag) for ab in absencedays: e = Event() e.name = ab.user.first_name + " " + ab.user.last_name + " abwesend" e.uid = "da-ab-" + str(ab.pk) e.begin = ab.start e.end = ab.end e.allday = True c.events.add(e) return HttpResponse(c, content_type='text/calendar') realm = "" response = HttpResponse() response.status_code = 401 response['WWW-Authenticate'] = 'Basic realm="%s"' % realm return response def getICSFileAll(request, ag): if 'HTTP_AUTHORIZATION' in request.META: auth = request.META['HTTP_AUTHORIZATION'].split() if len(auth) == 2: if auth[0].lower() == "basic": temp = base64.b64decode(auth[1] + "==") username = temp.decode("utf-8").split(":")[0] passwd = temp.decode("utf-8").split(":")[1] user = authenticate(username=username, password=passwd) if user is not None: if user.is_active: if user.profile.agency.pk == ag and user.has_perm('users.absencemanager'): request.user = user c = Calendar() absencedays = Absence.objects.filter(agency=ag) for ab in absencedays: e = Event() e.name = ab.user.first_name + " " + ab.user.last_name + " | " + ab.reason.name e.uid = "da-ab-" + str(ab.pk) e.begin = ab.start e.end = ab.end e.allday = True c.events.add(e) return HttpResponse(c, content_type='text/calendar') realm = "" response = HttpResponse() response.status_code = 401 response['WWW-Authenticate'] = 'Basic realm="%s"' % realm return response def getICSFileEx(request, code, ag): try: agency = Agency.objects.get(pk=ag) if agency != None and agency.agencycal_publicstatus == 1 and code == agency.agencycalurl: c = Calendar() absencedays = Absence.objects.filter(agency=ag) for ab in absencedays: e = Event() e.name = ab.user.first_name + " " + ab.user.last_name + " abwesend " e.uid = "da-ab-" + str(ab.pk) e.begin = ab.start e.end = ab.end e.allday = True c.events.add(e) return HttpResponse(c, content_type='text/calendar') else: realm = "" response = HttpResponse() response.status_code = 401 return response except: realm = "" response = HttpResponse() response.status_code = 401 return response def getICSFileExAll(request, code, ag): try: agency = Agency.objects.get(pk=ag) if agency != None and agency.agencycal_publicstatus == 1 and code == agency.agencycalurl_all: c = Calendar() absencedays = Absence.objects.filter(agency=ag) for ab in absencedays: e = Event() e.name = ab.user.first_name + " " + ab.user.last_name + " | " + ab.reason.name e.uid = "da-ab-" + str(ab.pk) e.begin = ab.start e.end = ab.end e.allday = True c.events.add(e) return HttpResponse(c, content_type='text/calendar') else: realm = "" response = HttpResponse() response.status_code = 401 return response except: realm = "" response = HttpResponse() response.status_code = 401 return response ''' Standardstruktur laden 4x Verbünde automatisch übernehmen --> Die 4 Verbünde aus der VVE Geschäftsstelle ''' def loadPreStructure(agency): ########## VERMARKTEN a_vermarkten = Areas(agency=agency, name="Vermarkten", color="#27ae60", desc="", created_area_by=None) a_vermarkten.save() a_vermarkten_tasks = ["Bewertungen", "Empfehlungsmanagement", "ERGO Mein Lokales Marketing", "Kampagnenmanagement", "Google My Business", "Hybride Agentur", "Social Media", "Zielgruppen"] for l in a_vermarkten_tasks: temp = Tasks(agency=agency, area=a_vermarkten, name=l) temp.save() # VERKAUFEN a_verkaufen = Areas(agency=agency, name="Verkaufen", color="#8e44ad", desc="", created_area_by=None) a_verkaufen.save() a_verkaufen_tasks = ["Aktionen", "Antragsprozesse", "Cross-Selling", "Kooperationen", "Leads", "Skype-Beratung", "Telefon-Beratung", "Terminvorbereitung", "Verkaufsgespräch", "Terminnachbereitung", "Terminierung/KKM"] for l in a_verkaufen_tasks: temp = Tasks(agency=agency, area=a_verkaufen, name=l) temp.save() # VERWALTEN a_verwalten = Areas(agency=agency, name="Verwalten", color="#f39c12", desc="", created_area_by=None) a_verwalten.save() a_verwalten_tasks = ["Agenturverwaltung", "Vertragsverwaltung", "EASY Anwendungen", "Host-Anwendungen", "Fremdverträge", "Kundenanschreiben", "Schaden und Leistung", "Textbaustein"] for l in a_verwalten_tasks: temp = Tasks(agency=agency, area=a_verwalten, name=l) temp.save() # BÜRPO INTERN a_buerointern = Areas(agency=agency, name="Büroabläufe intern", color="#c0392b", desc="", created_area_by=None) a_buerointern.save() a_buero_tasks = ["Bestellungen", "Büroordnung", "Post", "Technik"] for l in a_buero_tasks: temp = Tasks(agency=agency, area=a_buerointern, name=l) temp.save() # AG-Netzwork Joins # Join ID 8, 7, 6, 5 try: agn_8 = AgencyNetwork.objects.get(pk=8) agn_8.members.add(agency) agn_7 = AgencyNetwork.objects.get(pk=7) agn_7.members.add(agency) agn_6 = AgencyNetwork.objects.get(pk=6) agn_6.members.add(agency) agn_5 = AgencyNetwork.objects.get(pk=5) agn_5.members.add(agency) except: pass # CREATE WELCOME NEWS welcome_news = News(agency=agency, name="Herzlich Willkommen in der Digitalen Agentur", content='

Hallo lieber DA-Nutzer,

nicht erschrecken, wir haben für Sie schon einmal eine erste News mit allen wichtigen Informationen rund um diese Anwendung angelegt. 

Was bietet mir die Digitale Agentur für den Alltag?

Bilder sagen mehr als tausend Worte - Videos sagen mehr als tausend Bilder. Hier haben wir für Sie unser Produktvideo verlinkt, um Ihnen die wesentlichen Funktionen noch einmal vorzustellen:


Womit fangen Sie nun am besten an?

Damit Ihnen die ersten Schritte ein bisschen leichter fallen, haben wir für Sie eine Checkliste angelegt, die Ihnen die wichtigsten Einstellungen einmal zeigt. Die Checkliste erreichen Sie über den folgenden Link: digitale-agentur.com/article/erste-schritte/

Wo kann ich mir Hilfe bei Fragen holen?

Auf unserer Website finden Sie viele interessante und hilfreiche Kategorien und Artikel zur Arbeit mit der Anwendung. Wenn Sie also mal eine Frage haben oder sich inspirieren lassen wollen. Schauen Sie hier gerne vorbei: digitale-agentur.com

Bei inhaltlichen und technischen Fragen rund um die Anwendung klicken Sie einfach Links in der Navigation auf die Schaltfläche "Support", um Ihre Frage an unser Support-Team zu stellen.

Nun fürs erste aber genug - wir wünschen Ihnen viel Spaß und Erfolg mit der Digitalen Agentur!

Viele Grüße aus Hamburg ;)
Ihr DA-Team

') welcome_news.save() # ORGANIZER hw = QuickLinks(agency=agency, name="Hilfe und Wiki", link="https://digitale-agentur.com") hw.save() vve = QuickLinks(agency=agency, name="myvve", link="https://myvve.de") vve.save() def randomString(stringLength=10): """Generate a random string of fixed length """ letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(stringLength)) def randomStringNum(stringLength=20): """Generate a random string of fixed length """ lettersAndNumbers = string.ascii_lowercase + string.digits + string.ascii_uppercase return ''.join(random.choice(lettersAndNumbers) for i in range(stringLength)) @login_required def toUpdate(request): # NO AGENVYJOBS # CREATE DEFAULT ''' Agenturleiter Außendienst Innendienst Auszubildender ''' if len(request.user.profile.agency.agencycalurl) == 0: request.user.profile.agency.agencycalurl = randomStringNum(30) request.user.profile.agency.agencycalurl_all = randomStringNum(30) request.user.profile.agency.save() print("CAL-URLS updated for " + str(request.user.profile.agency.pk)) agencyjobsobject = AgencyJob.objects.filter(agency__pk=request.user.profile.agency.pk) if(len(agencyjobsobject) == 0): defaultAgencyJobs = ['Agenturleiter', 'Außendienst', 'Innendienst', 'Auszubildender'] for ele in defaultAgencyJobs: tempAgencyJob = AgencyJob(name=ele, agency=request.user.profile.agency) tempAgencyJob.save() agencygroups = AgencyGroup.objects.filter(agency__pk=request.user.profile.agency.pk) if(len(agencygroups) == 0): print("default groups not existing - creating") # MITARBEITER letters = string.ascii_lowercase temgroup_mitarbeiter = Group(name=str(request.user.profile.agency.pk) + "_" + randomString(8)) temgroup_mitarbeiter.save() temgroup_mitarbeiter_ag = AgencyGroup(savefordel=True, group=temgroup_mitarbeiter, agency=request.user.profile.agency, agencygroupname="Mitarbeiter") temgroup_mitarbeiter_ag.save() # VERWALTUNG temgroup_verwaltung = Group(name=str(request.user.profile.agency.pk) + "_" + randomString(8)) temgroup_verwaltung.save() temgroup_verwaltung_ag = AgencyGroup(savefordel=True, is_admin=True, group=temgroup_verwaltung, agency=request.user.profile.agency, agencygroupname="Administratoren") temgroup_verwaltung_ag.save() #print("default groups created...adding users...") users_of_agency = User.objects.filter(profile__agency__pk=request.user.profile.agency.pk) for user in users_of_agency: #print(temgroup_verwaltung_ag) #print(temgroup_verwaltung_ag.group) temgroup_verwaltung_ag.group.user_set.add(user) temgroup_mitarbeiter_ag.group.user_set.add(user) # ADDING ALL RIGHTS TO GROUP "VERWALTUNG" perms = AgencyGroup._meta.permissions for p in perms: tempperm = Permission.objects.get(codename=p[0]) temgroup_verwaltung_ag.group.permissions.add(tempperm) #print("default groups created and users added") else: #print("default groups existing") pass # UPDATE - Notfallhilfe # Gruppe Notfallhilfe wird hinzugefügt, wenn die Anzahl der Gruppen savefordel=True zwei ist if (len(AgencyGroup.objects.filter(agency=request.user.profile.agency, savefordel=True)) == 2): #print("missing recoverdir-group...adding") # Notfallhilfe letters = string.ascii_lowercase temgroup_Notfallhilfe = Group(name=str(request.user.profile.agency.pk) + "_" + randomString(8)) temgroup_Notfallhilfe.save() temgroup_Notfallhilfe_ag = AgencyGroup(savefordel=True, group=temgroup_Notfallhilfe, agency=request.user.profile.agency, agencygroupname="Notfallhilfe") temgroup_Notfallhilfe_ag.save() recoverdirmanagingperm = Permission.objects.get(codename='recoverdirmanager') temgroup_Notfallhilfe_ag.group.permissions.add(recoverdirmanagingperm) #print("recoverdirgroup added and perms set") # CHECK FOR ALL POSSIBLE RIGHTS ON ADMINGROUP m2m_changed.disconnect(adjust_group_notifications_permission, sender=Group.permissions.through) ag_admingroup = list(AgencyGroup.objects.filter(agency=request.user.profile.agency, is_admin=True))[0] perms = AgencyGroup._meta.permissions for p in perms: tempperm = Permission.objects.get(codename=p[0]) ag_admingroup.group.permissions.add(tempperm) # INITIAL ROOT DIR rootdir = DataDir.objects.filter(is_root=True, agency__pk=request.user.profile.agency.pk) if(len(rootdir) == 0): #print("NO MAIN DIR FOUND - CREATE") rootdir = DataDir(is_root=True, agency=request.user.profile.agency) rootdir.save() #print("AGENCY ROOT DIR CREATED") else: pass #print("MAIN ROOT DIR FOUND - FILESMODULE READY") # CHECK IF AGENCY DIRS EXIST path = settings.MEDIA_ROOT + "/agencydata/agency_" + str(request.user.profile.agency.pk) if(os.path.isdir(path) == False): # CREATE AGENCY DEFAULT DIRS os.mkdir(os.path.join(settings.MEDIA_ROOT + "/agencydata/", "agency_" + str(request.user.profile.agency.pk))) os.mkdir(os.path.join(settings.MEDIA_ROOT + "/agencydata/", "agency_" + str(request.user.profile.agency.pk) + "/files")) os.mkdir(os.path.join(settings.MEDIA_ROOT + "/agencydata/", "agency_" + str(request.user.profile.agency.pk) + "/agencystats")) os.mkdir(os.path.join(settings.MEDIA_ROOT + "/agencydata/", "agency_" + str(request.user.profile.agency.pk) + "/agencystats/profilepics")) # DEF STANDARD DIR defstandard = DataDir.objects.filter(is_defaultstandard=True, agency__pk=request.user.profile.agency.pk) if(len(defstandard) == 0): #print("NO DEF STANDARD FOUND - CREATE") rootdir = list(DataDir.objects.filter(is_root=True, agency__pk=request.user.profile.agency.pk))[0] defstandard = DataDir(is_defaultstandard=True, agency=request.user.profile.agency, name="Standards Uploadbereich", parent_id=rootdir.pk) defstandard.save() #print("AGENCY DEF STANDARD DIR CREATED") else: #print("AGENCY DEF STANDARD DIR - FILESMODULE READY") pass # CHANGE RIGHTS ORGNAIZER admingroups = AgencyGroup.objects.filter(is_admin=True) for a in admingroups: a.group.permissions.add(Permission.objects.get(codename="moduleorganizer")) a.group.permissions.add(Permission.objects.get(codename="agencynetwork")) m2m_changed.connect(adjust_group_notifications_permission, sender=Group.permissions.through) # USER TIME MODEL usersofagency = User.objects.filter(profile__agency=request.user.profile.agency) for u in usersofagency: # CREATE USERTIME-OBJECT if(len(UserTime.objects.filter(user=u)) == 0): usertime_new = UserTime(user=u) usertime_new.save() else: ut = UserTime.objects.get(user=u) if(ut.loose_holidedate == "2020-" or ut.loose_holidedate == "2021-"): ut.loose_holidedate = "30.04" ut.save() def onlyRD(request): if request.method == "POST": rdform = FormRD(request.POST) if rdform.is_valid(): rd = RegNotfallhilfe() rd.mail = rdform.cleaned_data.get('mail') rd.name = rdform.cleaned_data.get('name') rd.persnumber = rdform.cleaned_data.get("persnumber") rd.mitgliedsnummer = rdform.cleaned_data.get("mitgliedsnummer") rd.plz = rdform.cleaned_data.get("plz") rd.stadt = rdform.cleaned_data.get("stadt") rd.street = rdform.cleaned_data.get("street") rd.data_to_vh = True rd.rabatt = False rd.save() return render (request, 'users/rdorder_complete.html') else: messages.success(request, f'Bitte geben Sie korrekte Daten ein!') context = { "form" : FormRD(request.POST) } return render (request, 'users/register_rd.html',context) else: context = { "form" : FormRD() } return render (request, 'users/register_rd.html',context) ''' Neue Agentur UND Notfallhilfe bestellen ''' from django.views.decorators.csrf import csrf_protect @csrf_protect def registerNewAgencyRD(request): if request.method == "POST": newagencyform = NewAgencyFormRD(request.POST) if newagencyform.is_valid(): # Check Mail email = newagencyform.cleaned_data.get('mail') mailset = User.objects.filter(email=email) if(len(mailset) == 0): # AGENTURREGISTRIERUNG newuser_name = newagencyform.cleaned_data.get('first_name') + ' ' + newagencyform.cleaned_data.get('last_name') agency = Agency() agency.name = newagencyform.cleaned_data.get("agencyname") agency.vve = newagencyform.cleaned_data.get("vve") agency.street = newagencyform.cleaned_data.get("street") agency.city = newagencyform.cleaned_data.get("stadt") agency.plz = newagencyform.cleaned_data.get("plz") agency.save() loadPreStructure(agency) pr=Profile() pr.agency=agency user = "" try: user=User.objects.create_user(email, email, randomString(30)) except: user = User.objects.get(username=email) user.first_name = newagencyform.cleaned_data.get('first_name') user.last_name = newagencyform.cleaned_data.get('last_name') pr.user=user pr.save() user.profile = pr user.save() msg_html = render_to_string('users/register_mail.html', {'username': newuser_name}) # NOTFALLHILFE-DATEN SPEICHERN rd = RegNotfallhilfe() rd.mail = email rd.name = newagencyform.cleaned_data.get('first_name') + ' ' + newagencyform.cleaned_data.get('last_name') rd.persnumber = newagencyform.cleaned_data.get("persnumber") rd.mitgliedsnummer = newagencyform.cleaned_data.get("vve") rd.plz = newagencyform.cleaned_data.get("plz") rd.stadt = newagencyform.cleaned_data.get("stadt") rd.street = newagencyform.cleaned_data.get("street") rd.data_to_vh = True rd.rabatt = True rd.save() # E-Mail für Passwort-Setzung! form = PasswordResetForm({'email': email}) if form.is_valid(): form.save(request=request,html_email_template_name='users/password_reset_mail.html') return render (request, 'users/registercomplete.html') else: messages.success(request, f'Diese E-Mailadresse ist bereits vergeben!') context = { "form" : NewAgencyFormRD(request.POST) } return render (request, 'users/register_da_rd.html',context) else: messages.success(request, f'Bitte die korrekten Symbole aus dem Bild eingeben!') context = { "form" : NewAgencyForm(request.POST) } return render (request, 'users/register_da_rd.html',context) else: context = { "form" : NewAgencyFormRD() } return render (request, 'users/register_da_rd.html',context) ''' Neue Agentur registrieren ''' def registerNewAgency(request): if request.method == "POST": newagencyform = NewAgencyForm(request.POST) if newagencyform.is_valid(): # Check Mail email = newagencyform.cleaned_data.get('mail') mailset = User.objects.filter(email=email) if(len(mailset) == 0): newuser_name = newagencyform.cleaned_data.get('first_name') + ' ' + newagencyform.cleaned_data.get('last_name') agency = Agency() agency.name = newagencyform.cleaned_data.get("agencyname") agency.vve = newagencyform.cleaned_data.get("vve") agency.save() loadPreStructure(agency) pr=Profile() pr.agency=agency user = "" try: user=User.objects.create_user(email, email, randomString(30)) except: user = User.objects.get(username=email) user.first_name = newagencyform.cleaned_data.get('first_name') user.last_name = newagencyform.cleaned_data.get('last_name') pr.user=user pr.save() user.profile = pr user.save() msg_html = render_to_string('users/register_mail.html', {'username': newuser_name}) # E-Mail für Passwort-Setzung! form = PasswordResetForm({'email': email}) if form.is_valid(): form.save(request=request,html_email_template_name='users/password_reset_mail.html') return render (request, 'users/registercomplete.html') ''' send_mail( 'Agenturanmeldung', 'Hallo ' + newagencyform.cleaned_data.get('first_name') + ' ' + newagencyform.cleaned_data.get('last_name') + '! Bitte setzen sie sich auf https://app.digitale-agentur.com/password-reset/ ein Passwort. Anschließend können Sie weitere Details Ihrer Agentur eingeben.', 'noreply@digitale-agentur.com', [email], html_message=msg_html, fail_silently=True ) ''' return render (request, 'users/registercomplete.html') else: messages.success(request, f'Diese E-Mailadresse ist bereits vergeben!') context = { "form" : NewAgencyForm(request.POST) } return render (request, 'users/register.html',context) else: messages.success(request, f'Bitte die korrekten Symbole aus dem Bild eingeben!') context = { "form" : NewAgencyForm(request.POST) } return render (request, 'users/register.html',context) else: context = { "form" : NewAgencyForm() } return render (request, 'users/register.html',context) class AgencyCreateView(CreateView): model = User fields = ['first_name', 'last_name','username', 'email'] success_url = '/register/done' def form_valid(self, form): # Send message to the site messages.success(self.request, f'Agentur erstellt! Es wurde eine E-Mail verschickt mit weitere Infos zur Passworterstellung.') # SAVE OBJECTS TO SIGNALE! agency = Agency() agency.name = self.request.POST.get("agency_name") agency.save() loadPreStructure(agency) newuser_name = form.cleaned_data.get('first_name') + ' ' + form.cleaned_data.get('last_name') form.instance.agency = agency form.instance.parent = None msg_html = render_to_string('users/register_mail.html', {'username': newuser_name}) # E-Mail für Passwort-Setzung! send_mail( 'Agenturanmeldung', 'Hallo ' + form.cleaned_data.get('first_name') + ' ' + form.cleaned_data.get('last_name') + '! Bitte setzen sie sich auf https://app.digitale-agentur.com/password-reset/ ein Passwort. Anschließend können Sie weitere Details Ihrer Agentur eingeben.', 'noreply@digitale-agentur.com', [form.cleaned_data.get('email')], html_message=msg_html, fail_silently=True ) return super().form_valid(form) from auditlog.models import LogEntry @login_required def showUserLog(request, pk): if (request.user.pk == pk): logdata = LogEntry.objects.filter(object_pk=request.user.pk)[:50] logdata_logins = [] for ele in reversed(logdata): try: datestring = json.loads(ele.changes)["last_login"][1] datestring = datestring.split(".")[0] logdata_logins.append(datetime.strptime(datestring, '%Y-%m-%d %H:%M:%S')) except: pass context = { 'logdata' : logdata_logins } return render(request, 'users/userlog.html', context) else: context = {} return render(request, 'users/userlog_forbidden.html', context) @login_required def dashboard(request): # UPDATE FUNCTIONS BY NEW MODEL-CHANGES FOR COPIEN SOME DATA toUpdate(request) #storageinfo = sys.getfilesystemencoding() context = { 'active_link' : 'dashboard', #"systemencode" : storageinfo } # Adding active_link # Loading only user same agency # Change context and return for template-data # # Get all Users of the Same Agency as logged user standards_of_agency = Standards.objects.filter(agency__pk=request.user.profile.agency.pk).filter(public=True).exclude(area=None).exclude(task=None).order_by('-last_modified_on')[:5] filterdate = datetime.now() #news = News.objects.filter(agency__pk=request.user.profile.agency.pk).filter(go_online_on__let=filterdate).filter(go_offline_on__get=filterdate).order_by('-go_online_on')[:4] news_all = News.objects.filter(agency__pk=request.user.profile.agency.pk).filter(go_online_on__lt=filterdate).filter(go_offline_on__gt=filterdate).order_by('-go_online_on') | News.objects.filter(agency__pk=request.user.profile.agency.pk).filter(go_online_on__lt=filterdate).filter(go_offline_on__isnull=True).order_by('-go_online_on') # Maximal fünf News final zur Seite schicken! news = [] for n in news_all: if len(news) < 5: news.append(n) context.update({'active_link' : 'dashboard', 'standards_of_agency' : standards_of_agency, 'news' : news}) # GET ACUTAL ABSENCES today = date.today() acutal_absences = Absence.objects.filter(agency=request.user.profile.agency, end__gte=today, start__lte=today, confirm_status=0).order_by('user') context.update({'acutal_absences' : acutal_absences}) return render (request, 'users/dashboard.html', context) class UsersManagement(LoginRequiredMixin, ListView): model = User # Adding active_link # Loading only user same agency # Change context and return for template-data def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # Get all Users of the Same Agency as logged user users_of_agency = User.objects.filter(profile__agency__pk=self.request.user.profile.agency.pk).order_by('last_name') context.update({'active_link' : 'usersmanagement', 'users_of_agency':users_of_agency}) return context ''' Class AddNewUser() Erstellt einen neuen Nutzer mit SIGNALS, Profile und Agency (des aktuellen Users mit Rechten) ''' class UsersCreateUser(LoginRequiredMixin, CreateView): model = User fields = ['first_name', 'last_name', 'email'] success_url = '/settings/newuser/s2/' # Adding active_link def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({'active_link' : 'settings'}) return context def form_valid(self, form): # Send message to the site messages.success(self.request, f'Neuer Mitarbeiter angelegt!') # SAVE OBJECTS TO SIGNALE! form.instance.agency = self.request.user.profile.agency form.instance.parent = None newuser_name = form.cleaned_data.get('first_name') + " " + form.cleaned_data.get('last_name') msg_html = render_to_string('users/newusers_email.html', {'username': newuser_name}) ''' if(self.request.POST.get("sendmailnewuser")): send_mail( self.request.user.profile.agency.name + ' Account', 'Hallo ' + form.cleaned_data.get('first_name') + ' ' + form.cleaned_data.get('last_name') + '! Bitte setzen sie sich auf https://app.digitale-agentur.com/password-reset/ ein Passwort.', 'noreply@digitale-agentur.com', [form.cleaned_data.get('email')], html_message=msg_html, fail_silently=True, ) ''' return super().form_valid(form) # USER muss eingeloggt sein, um diese Seite zu sehen @login_required def profile(request): if request.method == 'POST': u_form = UsersChangeProfil(request.POST, instance=request.user) if u_form.is_valid(): u_form.save() prename = request.user.first_name name = request.user.last_name messages.success(request, f'Daten für {prename} {name} aktualisiert!') # Daten neu laden und nicht die "Mächten sie die Daten speichern...?" return redirect('users-dashboard') else: # Form in Klammern sind die aktuellen Daten :) u_form = UsersChangeProfil(instance=request.user) #p_form = UsersAddProfileForm(instance=request.user.profile) context = { 'u_form' : u_form, #'p_form' : p_form, 'active_link' : 'dashboard' } return render(request, 'users/profile.html', context) # Hier andere Nutzer ändern, wenn man Usersmanagement darf! class UserManagementUpdateForm(LoginRequiredMixin, UpdateView): model = Profile labels = { "phoneland" : "Telefon", "phonemobile" : "Mobil", "compfunc" : "Agenturfunktion", } fields = ['phoneland','phonemobile','compfunc'] # Update der Zugrifssrechte eines Users class UsersPermUpdateView(LoginRequiredMixin, View): template_name = 'users/users_perm.html' form_class = UsersPermForm success_url = '/dashboard/usersman/' # Form wird geladen; Checkboxen werden vorbereitet und hier rausgerendert. def get(self,request,*args, **kwargs): # User ist der hier Aufgerufene, bzw. das Profil! user_tochange = Profile.objects.get(pk=kwargs['pk']).user return render (request, self.template_name, {'form':self.form_class(user_tochange), 'active_link': 'usersmanagement', 'user_tochange': user_tochange}) # Handle POST GTTP requests def post(self, request, *args, **kwargs): permissions_loaded = dict(request.POST.lists()) user_tochange = Profile.objects.get(pk=kwargs['pk']).user # ITERATION Über alle Elemente gehen und Rechte entziehen (nicht vorhanden) oder adden (wenn vorhanden) # Hat ein user ein Recht NICHT, ist es NICHT in permissions # LOAD PERMISSIONS temprof = Profile for ele in temprof._meta.permissions: tempperm = Permission.objects.get(codename=ele[0]) if ele[0] in permissions_loaded: user_tochange.user_permissions.add(tempperm) else: # Eingeloggter User darf sich nicht selbst die Userverwaltungsrechte entziehen if user_tochange == request.user and ele[0]=='usermanager': messages.warning(request, f'Benutzerverwaltungsrechte für {user_tochange.first_name} {user_tochange.last_name} kann nicht entfernt werden.') else: user_tochange.user_permissions.remove(tempperm) user_tochange.save() messages.success(request, f'Berechtigungen für {user_tochange.first_name} {user_tochange.last_name} aktualisiert!') return HttpResponseRedirect('/dashboard/usersman/') # Benutzerprofil wird aktualisiert @login_required def ProfileUpdateView(request, pk): prof_user = User.objects.get(profile__pk=pk) if request.method == 'POST': profileform_form = UsersAddProfileForm(request.POST, request.FILES, instance=prof_user.profile) #profileform_parents = UsersAddProfileFormParents(request.POST, instance=request.user) prename = prof_user.first_name name = prof_user.last_name if profileform_form.is_valid(): profileform_form.save() messages.success(request, f'Daten für {prename} {name} aktualisiert!') return redirect('users-management') else: # Form in Klammern sind die aktuellen Daten :) profileform_form = UsersAddProfileForm(instance=prof_user.profile) # Nur User, die im Organigramm auch sichtbar sein, können ausgewählt werden possible_users = User.objects.filter(profile__agency__pk=prof_user.profile.agency.pk).filter(profile__visible=True) context = { 'prof_user' : prof_user, 'profileform_form' : profileform_form, 'active_link' : 'usersmanagement', 'possible_users' : possible_users } return render(request, 'users/profile_update.html', context) ''' Set users Parent by AJAX ''' @login_required def setuserparent(request): if request.method == 'GET': if request.GET['action'] == 'adduserp': userid = request.GET['objectid'] toadd = request.GET['userid'] toadd_user = User.objects.get(pk=toadd) workinguser = User.objects.get(pk=userid) username_clean = toadd_user.first_name + " " + toadd_user.last_name workinguser.profile.parent = toadd_user workinguser.save() # Getting Remaining-Users possible_users = User.objects.filter(profile__agency__pk=request.user.profile.agency.pk) possible_users_js = list(possible_users.values()) # Cleaned out, that only data is neede will send to the side (first/last-name and id) final_possible_users = {} for ele in possible_users_js: final_possible_users.update({'first_name':ele['first_name'],'last_name':ele['last_name'],'id':ele['id']}) # Counter for remaining users to show/hide "Keine Mitarbeiter"-Div return JsonResponse({'userid' : userid, 'username_clean' : username_clean, 'remaining_users':possible_users_js}) else: return HttpResponse("Request method is not a GET") @login_required def changeonlinestat(request): if request.method == 'GET': request.user.profile.onlinestatus = request.GET["newstat"] request.user.save() return JsonResponse({"newstat" : request.GET["newstat"]}) ''' # DELETE A USER Hier wird das Profil gelöscht, aber damit auch der User. Zusätzlich werden alle Standards, Bereiche und Tasks des zu löschenden Nutzers dem User zugeschrieben, welcher eingeloggt ist. Das passiert VOR dem löschen! ''' import csv @login_required def getDataFromToDelUser(request, pk): if(request.method == "GET"): user = User.objects.get(pk=pk) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename="DA-Export_'+ user.first_name + "_" + user.last_name + '.csv"' writer = csv.writer(response) # TASK: Hier besprechen, ob das Recht als Benutzermanager ausreicht! if(request.user.has_perm("users.usermanager") and user.profile.agency == request.user.profile.agency): user_absences = Absence.objects.filter(agency=request.user.profile.agency, user=user).order_by("-start") for ab in user_absences: status = "OK" if(ab.confirm_status == 1 or ab.confirm_status == 2): status = "Abgelehnt" writer.writerow(['Abwesenheit', str(ab.start), str(ab.end), 'Grund: '+ab.reason.name, 'Status: '+status]) user_workdays = Workday.objects.filter(agency=request.user.profile.agency, user=user).order_by("-start") for wd in user_workdays: breaks = Breaks.objects.filter(agency=request.user.profile.agency, user=user, workday=wd) breaks_string = "" for b in breaks: breaks_string += str(b.start) + " bis " + str(b.end) + ", " writer.writerow(['Arbeitstag', str(wd.start), str(wd.end), 'Pausen: ' + breaks_string]) return response else: pass class ProfileDeleteView(LoginRequiredMixin, DeleteView): model = User success_url = '/dasettings/main' template_name = 'users/user_confirm_delete.html' # Adding active_link def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # Hier Daten zusammenstellen, damit alle Daten bzgl Vertrag nicht verloren gehen (Zeiterfassung, Urlaub und Abwesenheiten) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename="file.csv"' writer = csv.writer(response) writer.writerow(['1001', 'John', 'Domil', 'CA']) writer.writerow(['1002', 'Amit', 'Mukharji', 'LA', '"Testing"']) context.update({"response" : response}) #print(response) return context def delete(self, request, *args, **kwargs): user = User.objects.get(pk=kwargs['pk']) logged_user = request.user ''' ALTER LÖSCHBEREICH - User wird einfach entfernt ''' ''' areas_fs = Areas.objects.filter(created_area_by=user) for a in areas_fs: a.created_area_by = logged_user a.save() # ACHTUNG! Bei Tasks heißt es leider auch created_area... task_fs = Tasks.objects.filter(created_area_by=user) for t in task_fs: t.created_area_by = logged_user t.save() standards_fs = Standards.objects.filter(created_standard_by=user) #print(standards_fs) for a in standards_fs: a.created_standard_by = logged_user a.save() standards_fs = Standards.objects.filter(last_modified_by=user) for a in standards_fs: a.last_modified_by = logged_user a.save() standards_fs = Standards.objects.filter(published_by=user) for a in standards_fs: a.published_by = logged_user a.save() ''' response = super(ProfileDeleteView, self).delete(request, *args, **kwargs) name = user.first_name + " " + user.last_name messages.success(request, f'Benutzer ' +name+ ' wurde gelöscht!') return response @login_required def agency(request): context = { 'active_link' : 'agencyinfo' } return render(request, 'users/agency.html', context) class AgencyUpdateView(LoginRequiredMixin, UpdateView): model = Agency form_class = AgencyUpdateForm template_name = 'users/agency_update.html' success_url = '/dashboard/agencyinfo' def get_context_data(self, **kwargs): context = super(AgencyUpdateView, self).get_context_data(**kwargs) context['active_link'] = 'agencyinfo' return context # PRIORISIERUNG ''' Es werden alle Aufgabenbereiche den Bereichen der Agentur zugeordnet und ausgegeben. ''' @login_required def UsersPrio(request, pk): user = User.objects.get(pk=pk) if(user.profile.agency.pk != request.user.profile.agency.pk): return HttpResponseRedirect('users-dashboard') else: prios = Prio.objects.filter(user__pk=pk) areas = Areas.objects.filter(agency__pk=request.user.profile.agency.pk) user_first_name = user.first_name user_last_name = user.last_name user_id = user.pk context = { 'active_link' : '', 'areas' : areas, 'user_first_name' : user_first_name, 'user_last_name' : user_last_name, 'user_id' : user_id, 'prios' : prios } return render(request, 'users/users_prio.html', context) ''' Ajax-Call für Prio.Updates seitens des Users im Profil ''' @login_required def UsersPrioUpdate(request): tempuser = User.objects.get(pk=request.GET['userid']) if request.method == 'GET' and tempuser.profile.agency.pk == request.user.profile.agency.pk: prio = Prio.objects.filter(user__pk=request.GET['userid']).filter(task__pk=request.GET['taskid']) prio = list(prio)[0] prio.prio = request.GET['value'] prio.save() return HttpResponse("udated...") else: return HttpResponse("Request method is not a GET") import re def cleanhtml(raw_html): cleanr = re.compile('<.*?>') cleantext = re.sub(cleanr, '', raw_html) return cleantext # Searxh for Standards by name, content, creator - standards needs to be public! @login_required def GlobalSearch(request): if request.method == 'GET': searchfor = request.GET['searchstring'] ag = request.user.profile.agency.pk res_standard = Standards.objects.filter(agency__pk=ag, public=True).filter(name__icontains=searchfor) | Standards.objects.filter(agency__pk=ag, public=True).filter(content__icontains=searchfor) | Standards.objects.filter(agency__pk=ag, public=True).filter(area__name__icontains=searchfor) | Standards.objects.filter(agency__pk=ag, public=True).filter(task__name__icontains=searchfor) | Standards.objects.filter(agency__pk=ag, public=True).filter(created_standard_by__last_name__icontains=searchfor)|Standards.objects.filter(agency__pk=ag, public=True).filter(created_standard_by__first_name__icontains=searchfor) res_news = News.objects.filter(agency__pk=ag).filter(name__icontains=searchfor) | News.objects.filter(agency__pk=ag).filter(content__icontains=searchfor) | News.objects.filter(agency__pk=ag).filter(created_by__last_name__icontains=searchfor)|News.objects.filter(agency__pk=ag).filter(created_by__first_name__icontains=searchfor) res_pass = AGPassword.objects.filter(agency__pk=ag).filter(name__icontains=searchfor) res_contacts = AGContacts.objects.filter(agency__pk=ag).filter(personname__icontains=searchfor) | AGContacts.objects.filter(agency__pk=ag).filter(name__icontains=searchfor) res_areas = Areas.objects.filter(agency__pk=ag).filter(name__icontains=searchfor) res_tasks = Tasks.objects.filter(agency__pk=ag).filter(name__icontains=searchfor) |Tasks.objects.filter(agency__pk=ag).filter(area__name__icontains=searchfor) res_pers = User.objects.filter(profile__agency__pk=ag).filter(first_name__icontains=searchfor) | User.objects.filter(profile__agency__pk=ag).filter(last_name__icontains=searchfor) links = QuickLinks.objects.filter(agency__pk=ag).filter(name__icontains=searchfor) | QuickLinks.objects.filter(agency__pk=ag).filter(link__icontains=searchfor) res_files = DataFile.objects.filter(agency__pk=ag).filter(name__icontains=searchfor) html = render_to_string('users/searchres.html', {'links': links, 'res_standard': res_standard, 'res_areas': res_areas, 'res_tasks': res_tasks, 'res_pers': res_pers, 'res_news' : res_news, 'res_pass' : res_pass, 'res_contacts' : res_contacts, 'res_files' : res_files, 'user' : request.user}) return HttpResponse(html) else: return HttpResponse("Request method is not a GET") @login_required def searchStandardRouter(request): if request.method == 'GET': return redirect('/standards/standard/'+request.GET['s_id']+'/single') else: return redirect('dashboard') ''' Hier werden die Zuständigkeiten eines Benutzers über alle Bereiche/Aufgaben hinweg gesetzt. Das Update erfolgt per Booleanfields. ''' @login_required def UsersAreaTaskUpdate(request, pk): user = User.objects.get(pk=pk) if request.user.profile.agency.pk != user.profile.agency.pk: return redirect('dashboard') else: finaldata = {} context = { 'active_link' : 'usersmanagement', 'user_id' : user.pk, } if request.method == 'POST': form = request.POST areatask_formdata = list(form) # CRSF-Token löschen del areatask_formdata[0] # Formular übertragen area_ids = [] task_ids = [] # Areas in Formular laden for ar in areatask_formdata: tempdata = ar.split("_") if(tempdata[0] == 'area'): area_ids.append(int(tempdata[1])) elif(tempdata[0] == 'task'): task_ids.append(int(tempdata[1])) # Alle Areas und Tasks laden areas = Areas.objects.filter(agency__pk=user.profile.agency.pk) tasks = Tasks.objects.filter(agency__pk=user.profile.agency.pk) # Prüfen, ob der User in Area ist oder nicht und ihn ggf. hinzufügen/entfernen for area in areas: if area.pk in area_ids: area.usersfield.add(user) else: area.usersfield.remove(user) area.save() ''' Prüfen, ob ein User einem Aufgabenbereich hinzugeprdnet ist. Ist er im Bereich, passiert nichts. Ist er nicht in diesem Bereich, wird er dem usersfield der Aufgabe und der Tabelle Prio hinzugeüfügt. Damit kann der User seine individuellen Prios im Profil anpassen. ''' for task in tasks: if task.pk in task_ids: prio_check = Prio.objects.filter(user__pk=pk, task=task) if(len(prio_check) == 0): prio = Prio(user=User.objects.get(pk=pk), task=task) prio.save() task.usersfield.add(user) else: task.usersfield.remove(user) Prio.objects.filter(user__pk=pk).filter(task__pk=task.pk).delete() task.save() username_message = user.first_name + " " + user.last_name messages.success(request, f'Zuständigkeiten für {username_message} aktualisiert!') return redirect('users-management') else: form = UserAreaTaskForm(user) user_first_name = user.first_name user_last_name = user.last_name user_id = user.pk context = { 'active_link' : '', 'user_first_name' : user_first_name, 'user_last_name' : user_last_name, 'user_id' : user_id, 'form' : form } return render(request, 'users/users_areatasks.html', context) @login_required def support(request): context = { 'active_link' : 'support', 'form' : SupportForm(request.user) } if request.method == 'POST': form = request.POST ''' fileblob = "" attachments=[] #myfile is the key of a multi value dictionary, values are the uploaded files for f in request.FILES.getlist('attachment_1'): #myfile is the name of your html file button filename = f.name attachment_type = filetype.guess(f) fileblob = str(base64.b64encode(f.read())) fileblob = fileblob[1 : : ] fileblob = fileblob[1 : : ] fileblob = fileblob[:-1:] attachments.append({str(filename) : "data:" + attachment_type.mime + ";base64," + fileblob}) fileblob = "data:" + attachment_type.mime + ";base64," + fileblob for f in request.FILES.getlist('attachment_2'): #myfile is the name of your html file button filename = f.name attachment_type = filetype.guess(f) fileblob = str(base64.b64encode(f.read())) fileblob = fileblob[1 : : ] fileblob = fileblob[1 : : ] fileblob = fileblob[:-1:] attachments.append({str(filename) : "data:" + attachment_type.mime + ";base64," + fileblob}) for f in request.FILES.getlist('attachment_2'): #myfile is the name of your html file button filename = f.name attachment_type = filetype.guess(f) fileblob = str(base64.b64encode(f.read())) fileblob = fileblob[1 : : ] fileblob = fileblob[1 : : ] fileblob = fileblob[:-1:] attachments.append({str(filename) : "data:" + attachment_type.mime + ";base64," + fileblob}) ''' #image = request.FILES supportdata = dict(form) # Data from Form to JSON-Format name = str(supportdata['name'][0]) mail = str(supportdata['mail'][0]) problemconc = str(supportdata['problemconc'][0]) problem = str(supportdata['problem'][0]) # HEADERS CURL headers = {'X-API-Key': 'F025A238EB74914E3653BA2989BFF7C4'} subject = "Digitale Agentur: " + str(problemconc) # TASK: Hier die Auswahl des DropDown in die API mit einbauen, damit das Ticket in das entsprechende Department läuft # DataJSON ostdata = { "topicId" : str(supportdata['department'][0]), "name": name, "email": mail, "subject": 'Digitale Agentur: '+problemconc, "ip": "1.1.1.1", "" "message": "*****************************\nAgentur: "+ request.user.profile.agency.name +" (ID: "+ str(request.user.profile.agency.pk) +")\nBenutzer: "+request.user.first_name+" "+request.user.last_name+" (ID: "+ str(request.user.pk) +")\nBrowser: " + request.META['HTTP_USER_AGENT'] + "\n*******************************\n\n" + problem #"attachments" : attachments } json_data = json.dumps(ostdata) r = requests.post("https://support.vh-solutions.de/api/http.php/tickets.json", data=json_data, headers=headers) # IF request FAILED error-Message if(r.status_code != 201): messages.warning(request, f'Supportanfrage fehlgeschlagen!' + str(r)) else: messages.success(request, f'Supportanfrage erfolgreich! Ihre Ticketnummer ist '+ str(r.json()) +'!') send_mail("Re: Digitale Agentur: " + str(problemconc) + " [#" + str(r.json()) + "]","Hallo " + name + ", wir haben Ihre Anfrage unter der Ticketnummer " + str(r.json()) + " aufgenommen. Vielen Dank. Ihr Team der Digitalen Agentur",'noreply@digitale-agentur.com',[mail],fail_silently=True) return render(request, 'users/support_done.html', context) else: return render(request, 'users/support.html', context) ''' Schickt eine E-Mail an den User inkl. Passwortlink zum zurücksetzen. ''' def sendpassmail(request): if(request.method == 'GET'): userid = request.GET['userid'] tempuser = User.objects.get(pk=userid) # E-Mail für Passwort-Setzung! form = PasswordResetForm({'email': tempuser.email}) if form.is_valid(): form.save(request=request,html_email_template_name='users/password_reset_mail.html') return render (request, 'users/registercomplete.html') return JsonResponse({'message' : 0}) def datenschutz(request): if request.user.is_authenticated: return render(request, 'users/datenschutz.html') else: return render(request, 'users/datenschutz_p.html') def impressum(request): if request.user.is_authenticated: return render(request, 'users/impressum.html') else: return render(request, 'users/impressum_p.html') ''' ERROR HANDLER VIEWS ''' def handler404(request, exception): context = {} response = render(request, "users/errors/404.html", context=context) response.status_code = 404 return response def handler500(request): context = {} response = render(request, "users/errors/500.html", context=context) response.status_code = 500 return response ''' CRONJOB FUNCTION ''' # CRONJOBS ALLE 5 MINUTEN def cronactions(request, code): data = {} if(code == settings.CRONAPIKEY): # NEWS CHECKING all_unnotifc_news = News.objects.filter(agnotify=False, go_online_on__lt=timezone.now()) allusers = User.objects.all() for news in all_unnotifc_news: targeturl = settings.BASE_URL + "news/news/" + str(news.pk) + "/single" # NEW NEWS FOUND WHICH HAVE TO GO ONLINE NOW! news.agnotify = True news.save() for user in allusers: # SEMI-SIGNAL FOR NEWS GOING ONLINE if(user.usernotifications.news_created_mail and news.agency == user.profile.agency): notificationtext = "Neue Agenturnews: " + news.name username = user.first_name + " " + user.last_name msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext, 'linktarget' : targeturl}) send_mail( 'Agentur-Benachrichtigung', 'Hallo ' + user.first_name + ' ' + user.last_name + '! ' + notificationtext, 'noreply@digitale-agentur.com', [user.email], html_message=msg_html, fail_silently=True, ) if(user.usernotifications.news_created_push and news.agency == user.profile.agency): newnotification = UserNotification(touser=user, notificationtext="Neue Agenturnews: " + news.name, notificationtype="agencynews", elementid=news.pk) newnotification.save() channel_layer = channels.layers.get_channel_layer() async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__News | Neue Agenturnews: " + news.name}) # LEXOFFICE TEST # HEADERS CURL ''' headers = { 'Authorization': 'Bearer 33bfb1b9-2994-4fd4-b447-1f4754a5c7cb', 'Content-Type': 'application/json', 'Accept': 'application/json', } # DataJSON lexdata = { "voucherDate": "2020-07-09T00:00:00.000+01:00", "address" : { "name" : "Agenturname XXX", "countryCode" : "DE" }, "totalPrice" : { "currency" : "EUR", }, "lineItems" : [ { "type" : "custom", "name" : "Monatsbeitrag", "quantity" : 1, "unitName" : "Stück", "unitPrice" : { "currency" : "EUR", "netAmount" : 10, "taxRatePercentage" : 16 }, }, { "type" : "custom", "name" : "Abwesenheitsmodul", "quantity" : 1, "unitName" : "Stück", "unitPrice" : { "currency" : "EUR", "netAmount" : 10, "taxRatePercentage" : 16 }, } ], "taxConditions": { "taxType": "net" }, "shippingConditions": { "shippingDate": "2020-07-09T00:00:00.000+01:00", "shippingType": "service" }, } json_data = json.dumps(lexdata) r = requests.get("https://api.lexoffice.io/v1/invoices/0f9b6a1d-1912-4a10-9926-7909e5580202", data=json_data, headers=headers) print(r) print(r.text) ''' else: print("API CODE FAILED") data.update({"status" : "failed"}) return JsonResponse(data) ''' LANDING PAGE ''' class landingPage(TemplateView): template_name = "users/landingpage.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) ''' Gibt False zurück, wenn der User an diesem Tag KEINE Abwesenheiten hat, ansonsten True! ''' def absencecheck(user, daytocheck): returnstat = False absencedays = Absence.objects.filter(agency=user.profile.agency, user=user, confirm_status=0) & (Absence.objects.filter(agency=user.profile.agency, user=user, start=daytocheck) | (Absence.objects.filter(agency=user.profile.agency, user=user, start__lt=daytocheck) & Absence.objects.filter(agency=user.profile.agency, user=user, end__gt=daytocheck)) | Absence.objects.filter(agency=user.profile.agency, user=user, end=daytocheck)) if(len(absencedays) > 0): returnstat = True return returnstat # CRONJOBS UM 00:05! def cronactionsdaily(request, code): data = {} today = date.today() mailstatus = "BEGIN CRONJOB DAILY" + str(today) if(code == settings.CRONAPIKEY): allusers = User.objects.all() ''' Pro User gibt es das Feld loose_holiday in der UserTime-Info. Ist dieser Tag vorbei, muss die Differenz der days_inuse des VORJHARES in den Rest das AKTUELLEN JAHRES gespeichert werden! ''' for user in allusers: mailstatus += "\n USER: " + user.first_name + " " + user.last_name + " ID: (" + str(user.pk) + ")" # REST URLAUB BERECHNUNG #try: usertimedata = UserTime.objects.get(user=user) day_tocheck = usertimedata.loose_holidedate.split(".")[0] month_tocheck = usertimedata.loose_holidedate.split(".")[1] month = today.month day = today.day if month < 10: month = "0" + str(month) day = today.day else: month = month if day < 10: day = "0" + str(day) else: day = day # Restetag erreicht, Reste ins nächste Jahr übertragen ''' DAS IST UNNÖTIG ''' ''' if(str(day_tocheck) == str(day) and str(month_tocheck) == str(month)): sourceyear = today.year this_year = list(UserYearAbsenceInfo.objects.filter(year=sourceyear, user=user))[0] next_year = list(UserYearAbsenceInfo.objects.filter(year=sourceyear+1, user=user))[0] next_year.restdays = this_year.days - this_year.days_inuse next_year.save() ''' # Arbeitstage beenden try: if(user.usertime.usetime): try: workdays = Workday.objects.filter(user=user, end=None) for wd in workdays: mailstatus += "\n WORKDAY AUTEND ID " + wd.pk wd.end = datetime(wd.start.year, wd.start.month, wd.start.day, 23, 59) wd.save() except: mailstatus += "ERROR WORKDAYS AUTO END" # AUTO ARBEITSTAGE HINZUFÜGEN try: yesterday = date.today() - timedelta(days=1) weekday = yesterday.weekday() workdays_yesterday = len(Workday.objects.filter(user=user, start__day=yesterday.day, start__month=yesterday.month, start__year=yesterday.year)) targettworktime = 0.0 # Mitarbeiter hat für den gestrigen Tag keine Zeiten erfasst, daher automatisch auf null wenn KEINE Abwesenheit eingetragen wurde if(weekday == 0): targettworktime = user.usertime.wd_mo if(weekday == 1): targettworktime = user.usertime.wd_tu if(weekday == 2): targettworktime = user.usertime.wd_we if(weekday == 3): targettworktime = user.usertime.wd_th if(weekday == 4): targettworktime = user.usertime.wd_fr if(weekday == 5): targettworktime = user.usertime.wd_sa if(weekday == 6): targettworktime = user.usertime.wd_so # Es wird nur ein Arbeitstag erstellt, wenn KEINE Abwesenheiten vorliegen und der Nutzer an diesem Tag arbeiten muss if(workdays_yesterday == 0 and absencecheck(user, yesterday) == False and targettworktime > 0.0 and user.usertime.usetime_start < today): workdaytemp = Workday(user=user, agency=user.profile.agency, start=datetime(yesterday.year, yesterday.month, yesterday.day, 8, 0), end=datetime(yesterday.year, yesterday.month, yesterday.day, 8, 0), target=targettworktime) workdaytemp.save() except: mailstatus += "ERROR AUTO ADDING WORKDAYS" try: # Erinnerungsmails/Push bei Vertretung verschicken one_week_later = date.today() + timedelta(days=7) repre_absence = Absence.objects.filter(representator=user, start=one_week_later, confirm_status=0) for r in repre_absence: if(r.representator.usernotifications.absence_user_is_rep_reminder_mail): sendMailNoti(" in einer Woche startet Ihre Vertretung für " + r.user.first_name + " " + r.user.last_name + "!", user) if(r.representator.usernotifications.absence_user_is_rep_reminder_push): newnotification = UserNotification(touser=user, notificationtext="Erinnerung für Abwesenheitsvertretung!", notificationtype="", elementid=r.pk) newnotification.save() channel_layer = channels.layers.get_channel_layer() async_to_sync(channel_layer.group_send)("user_" + str(user.pk), {'type' : 'pushhandler', 'pushtext' : "pushnotification__Abwesenheit | In einer Woche startet Ihre Vertretung für " + r.user.first_name + " " + r.user.last_name + "!"}) except: mailstatus += "ERROR REMINDER ABSENCEMAIL" data.update({"status " + str(user.pk) : "ok"}) except ObjectDoesNotExist: data.update({"status" + str(user.pk) : "no usertime found for " + user.get_full_name()}) mailstatus += "USER HAS NO USERTIMEOBJECT USER-ID: " + str(user.pk) else: data.update({"status" : "failed"}) send_mail( 'DAILYCRONJOB FEEDBACK', mailstatus, 'noreply@digitale-agentur.com', ["htrampe@gmail.com", "info@digitale-agentur.com"], fail_silently=True, ) return JsonResponse(data) #import datetime from django.db.models.signals import post_save from users.signals import save_newabsence from timemanagement.models import Workday, Breaks, AbsenceReason, FreeDays, Absence def recalculateAbsence(request, code): data = {} calcstat = "BEGIN RECALCULATE ABSENCE" today = date.today() year = today.year post_save.disconnect(save_newabsence, sender=Absence) if(code == settings.CRONAPIKEY): for user in User.objects.all(): calcstat += "\n USER " + str(user.pk) try: abinfo_lastyear = UserYearAbsenceInfo.objects.get(user=user, year=str(int(year)-1)) abinfo_thisyear = UserYearAbsenceInfo.objects.get(user=user, year=year) if(abinfo_lastyear.days_inuse > 0.0): abinfo_thisyear.restdays = abinfo_lastyear.days - abinfo_lastyear.days_inuse abinfo_thisyear.save() calcstat += " DAYS UPDATED - NEW RESTDAYS: " + str(abinfo_thisyear.restdays) for ab in Absence.objects.filter(user=user, start__year=year): if(ab.reason.is_holiday): calculateNewAbsenceDate(ab) daysinuse_thisyear = 0.0 for ab in Absence.objects.filter(user=user, start__year=year): daysinuse_thisyear += ab.holidays_normal calcstat += " NEW DAYSINUSE THIS YEAR " + str(daysinuse_thisyear) abinfo_thisyear.days_inuse = daysinuse_thisyear abinfo_thisyear.save() else: calcstat += " NO DAYS IN 2020 USED " except: calcstat += "ERROR LASTYEAR/THISYEAR USER " + str(user.pk) post_save.connect(save_newabsence, sender=Absence) send_mail( 'RECALCULATING ABSENCE YEAR INFO PROTOCOLL', calcstat, 'noreply@digitale-agentur.com', ["info@digitale-agentur.com"], #["htrampe@gmail.com"], fail_silently=True, ) return JsonResponse(data) def calculateNewAbsenceDate(instance): newdata = getFinalHolidayData(instance) abinfo = list(UserYearAbsenceInfo.objects.filter(user=instance.user, year=instance.start.year))[0] abinfo_lastyear = "" abinfo_nextyear = "" is_lastyear = False abinfo_lastyear = list(UserYearAbsenceInfo.objects.filter(user=instance.user, year=instance.start.year-1)) if(len(abinfo_lastyear) > 0): is_lastyear = True abinfo_lastyear = abinfo_lastyear[0] is_nextyear = False abinfo_nextyear = list(UserYearAbsenceInfo.objects.filter(user=instance.user, year=instance.start.year+1)) if(len(abinfo_nextyear) > 0): is_nextyear = True abinfo_nextyear = abinfo_nextyear[0] multiple_info_needays = False if(hasattr(newdata[3], "__len__")): multiple_info_needays = True # Gleiches Jahr MIT Rest if(multiple_info_needays and newdata[3][2] == False): # Rest ist positiv, daher bleibt rest übrig, rest wird in absence gespeichert und vom rest des Jahres-Restes abgezogen # Rest ist positiv, damit bleibt Rest übrig if(newdata[3][0] > 0): instance.holidays_rest = abinfo.restdays - newdata[3][0] instance.save() abinfo.restdays = newdata[3][0] abinfo.save() # Rest ist negativ elif(newdata[3][0] < 0): instance.holidays_rest = (abinfo.restdays - newdata[3][0]) - newdata[3][0]*(-1) instance.holidays_normal = newdata[3][0]*(-1) instance.save() abinfo.restdays = 0 abinfo.days_inuse = abinfo.days_inuse + newdata[3][0]*(-1) abinfo.save() # Rest ist Urlaubsdauer else: instance.holidays_rest = abinfo.restdays instance.save() #abinfo.days_inuse = abinfo.days_inuse + abinfo.restdays abinfo.restdays = 0 abinfo.save() # Gleiches Jahr ohne Rest elif(not multiple_info_needays): abinfo.days_inuse = abinfo.days_inuse + newdata[3] abinfo.save() instance.holidays_normal = newdata[3] instance.save() # Mehrere Jahre elif(multiple_info_needays and newdata[3][2] == True): abinfo.days_inuse = abinfo.days_inuse + newdata[3][0] abinfo.save() abinfo_nextyear.days_inuse = abinfo_nextyear.days_inuse + newdata[3][1] abinfo_nextyear.restdays = abinfo_nextyear.restdays - newdata[3][3] abinfo_nextyear.save() # Hier werden alle benötigten Tage von Vor- und Nächstem Jahr gespeichert instance.holidays_normal = newdata[3][0] instance.holidays_rest = 0 instance.holidays_normal_next = newdata[3][1] instance.holidays_rest_next = newdata[3][3] instance.save() ''' ABRECHNUNG CRON JOB ''' from dateutil.relativedelta import * def cronactionsbill(request, code): data = {} today = date.today() mailstatus = "BEGIN CRONJOB BILL" + str(today) if(code == settings.CRONAPIKEY): # Check, ob Rechnungen bezahlt wurden unpaid_bills = AgencyBills.objects.all() for bill in unpaid_bills: # Für jede Rechnung eine Anfrage an die LexOffice API und voucherStatus auslesen headers = { 'Authorization': 'Bearer ' + settings.LEX_API, 'Content-Type': 'application/json', 'Accept': 'application/json', } json_data = {} r = requests.get("https://api.lexoffice.io/v1/invoices/"+AgencyBills.objects.get(pk=bill.pk).lexid, data=json_data, headers=headers) if(json.loads(r.text)["voucherStatus"] == "paid"): bill.billstatus="paid" bill.save() else: bill.billstatus="open" bill.save() # Monatliche Berechnung # Alle Rechnungen laden, deren Letzter Tag HEUTE ist und bei ausgewähltem Paymentplan 1 eine neue Rechnung erstellen, Mailverschicke, Nutzeraccouns zählen und neue Rechnung in der Agentur hinterlegen new_bills = AgencyBills.objects.filter(end=today) for bill in new_bills: if bill.agency.paymentstatus == 0 and bill.agency.paymentplan == 1: agency = bill.agency month = today # 30 Tage weiter, nicht einen Monat! next_month = today + relativedelta(days=30) # USERCOUNT BERECHNEN usercount = len(User.objects.filter(profile__agency=agency)) if(usercount < 4): usercount = 0 else: usercount = usercount - 3 # HEADERS CURL headers = { 'Authorization': 'Bearer ' + settings.LEX_API, 'Content-Type': 'application/json', 'Accept': 'application/json', } plan = 1 start_date = month start_date_string = month.strftime("%d.%m.%Y") end_date = month + relativedelta(days=30) end_date_string= end_date.strftime("%d.%m.%Y") voucher_date_today = date.today().strftime("%Y-%m-%d") monthword = "Monat" lexdata = { "voucherDate": voucher_date_today + "T00:00:00.000+00:00", "address" : { "name" : agency.name, "street": agency.street, "zip": agency.plz, "city": agency.city, "countryCode" : "DE" }, "totalPrice" : { "currency" : "EUR", }, "lineItems" : [ { "type" : "custom", "name" : "Digitale Agentur: Grundbetrag für " + str(plan) + " " + monthword, "quantity" : 1, "unitName" : "Stück", "description" : "Zeitraum " + start_date_string + " - " + end_date_string, "unitPrice" : { "currency" : "EUR", "netAmount" : 21.00, "taxRatePercentage" : 19 }, }, { "type" : "custom", "name" : "Digitale Agentur: Zusätzliche Nutzer", "description" : "Zeitraum " + start_date_string + " - " + end_date_string, "quantity" : usercount, "unitName" : "Stück", "unitPrice" : { "currency" : "EUR", "netAmount" : 3, "taxRatePercentage" : 19 }, } ], "taxConditions": { "taxType": "net" }, #"paymentConditions": { # "paymentTermLabel": "Bitte zahlen Sie innerhalb von 14 Tagen.", # "paymentTermDuration": 14, #}, "shippingConditions": { #"shippingDate": voucher_date_today + "T00:00:00.000+00:00", "shippingType": "none" } } json_data = json.dumps(lexdata) # WIEDER RAUSNEHMEN # NEUE RECHNUNG ALs ENTWURF #r = requests.post("https://api.lexoffice.io/v1/invoices/", data=json_data, headers=headers) # RICHTIGE RECHNUNG r = requests.post("https://api.lexoffice.io/v1/invoices/?finalize=true", data=json_data, headers=headers) if(r.status_code == 201): try: response_text = json.loads(r.text) newbill_id = response_text["id"] # OrganizationId berechnen, wenn noch nicht gesetzt r = requests.get("https://api.lexoffice.io/v1/invoices/" + response_text["id"], data=json_data, headers=headers) response_text = json.loads(r.text) newbill = AgencyBills(agency=agency, lexid=newbill_id, billtype="invoice", billnumber=response_text["voucherNumber"], billstatus=response_text["voucherStatus"], start=start_date, end=end_date, plan=plan, usercount=usercount) newbill.save() mail_to_send = "" if(agency.payment_address == None): mail_to_send = agency.agency_email else: mail_to_send = agency.payment_address # BCC Mail with Object - NICHT DEN IMPORT VERGESSEN!!! email = EmailMultiAlternatives( 'Digitale Agentur | Rechnung ' + str(response_text["voucherNumber"]), 'Sehr geehrte Nutzer, hiermit erhalten Sie eine neue Rechnung für die Digitale Agentur. Ihr Team der Digitalen Agentur', 'noreply@digitale-agentur.com', [mail_to_send], ['info@digitale-agentur.com'], headers={}, ) headers = { 'Authorization': 'Bearer ' + settings.LEX_API, 'Content-Type': 'application/json', 'Accept': 'application/json', } lexdata = { "renderType" : "pdf" } json_data = json.dumps(lexdata) r_final = requests.get("https://api.lexoffice.io/v1/invoices/"+newbill_id+"/document", data=json_data, headers=headers) json.loads(r_final.text) base64String = requests.get("https://api.lexoffice.io/v1/files/"+json.loads(r_final.text)["documentFileId"]+"/", data=json_data, headers=headers) content = base64.b64decode(base64String.text) msg_html = render_to_string('users/newbill_mail.html', {}) email.attach_alternative(msg_html, "text/html") email.attach('Rechnung_' + str(response_text["voucherNumber"]) + '.pdf', content, "application/pdf") email.send() #send_mail('Digitale Agentur | Rechnung', 'Sehr geehrte Nutzer, es wurde eine Rechnung für Ihre Digitale Agentur erstellt. Diese können Sie unter Einstellungen, Abrechnung einsehen.','noreply@digitale-agentur.com',[mail_to_send],html_message=msg_html,fail_silently=True) data.update({"newBill_" + str(agency.pk) : newbill.lexid}) mailstatus += "NEW BILL FOR AGENCY " + str(agency.pk) except: mailstatus += "ERROR BY SENDING NEW MAIL TO " + str(agency.pk) else: data.update({"status" : "failed"}) send_mail( 'DAILYCRONJOB BILLS FEEDBACK', mailstatus, 'noreply@digitale-agentur.com', ["htrampe@gmail.com", "info@digitale-agentur.com"], fail_silently=True, ) return JsonResponse(data) def sendMailNoti(notificationtext, user_touched, linktarget=""): username = user_touched.first_name + " " + user_touched.last_name msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext, 'linktarget' : linktarget}) send_mail( 'Agentur-Benachrichtigung', 'Hallo ' + user_touched.first_name + ' ' + user_touched.last_name + '! ' + notificationtext, 'noreply@digitale-agentur.com', [user_touched.email], html_message=msg_html, fail_silently=True, ) def isAlive(request): return JsonResponse({"status" : True}) ''' AB HIER WIEDER RAUSNEHMEN ''' def getFinalHolidayData(abscence): user = abscence.user usertimedata = UserTime.objects.get(user=user) today = date.today() start_day_obj = abscence.start end_day_obj = abscence.end try: holidayloose_date = datetime.date(start_day_obj.year, int(usertimedata.loose_holidedate.split(".")[1]), int(usertimedata.loose_holidedate.split(".")[0])) except: holidayloose_date = datetime.date(2020, int(usertimedata.loose_holidedate.split(".")[1]), int(usertimedata.loose_holidedate.split(".")[0])) #start_half = abscence.start_ishalf #end_half = abscence.end_ishalf start_half = False if abscence.startday_info == "1" or abscence.startday_info == "2": start_half = True end_half = False if abscence.endday_info == "1" or abscence.endday_info == "2": end_half = True choosenyear = abscence.start.year yeardata = list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear))[0] holiday_thisyear = 0 holiday_lastyear = yeardata.restdays holiday_nextyear = 0 try: holiday_nextyear = list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear+1))[0].days - list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear+1))[0].days_inuse holiday_nextyear_rest = list(UserYearAbsenceInfo.objects.filter(user=user, agency=user.profile.agency, year=choosenyear+1))[0].restdays except: holiday_nextyear = yeardata.days # Urlaub innerhalb eines Jahres inkl. Prüfung auf Resturlaubsanspruch if(end_day_obj.year == start_day_obj.year): # Startt des Urlaubs NACH Verfallsdatum - nur aktuelles JAhr und die Zahl interessiert if(start_day_obj > holidayloose_date): need_days = (calculateHolidays(user, start_day_obj, end_day_obj, start_half, end_half))*(-1) holiday_thisyear = yeardata.days - yeardata.days_inuse - need_days else: need_days = (calculateHolidays(user, start_day_obj, end_day_obj, start_half, end_half))*(-1) # Kein Resturlaub if(yeardata.restdays == 0.0): holiday_thisyear = yeardata.days - yeardata.days_inuse - need_days # Resturlaub vorhanden, berechne mit Resturlaub else: holiday_lastyear = yeardata.restdays holiday_thisyear = yeardata.days - yeardata.days_inuse temp_holiday = holiday_lastyear - need_days if(temp_holiday < 0): holiday_lastyear = 0 holiday_thisyear = yeardata.days - yeardata.days_inuse + temp_holiday need_days = [temp_holiday, holiday_thisyear, False] else: holiday_lastyear = yeardata.restdays - need_days need_days = [temp_holiday, holiday_lastyear, False] # Urlaub geht über das nächstes Jahr hinweg else: two_years = True holiday_lastyear = yeardata.restdays date_splitter = datetime.date(end_day_obj.year, 1, 1) need_days_this = (calculateHolidays(user, start_day_obj, date_splitter, start_half, False))*(-1) need_days_next = (calculateHolidays(user, date_splitter, end_day_obj, False, end_half))*(-1) need_days = (calculateHolidays(user, start_day_obj, date_splitter, start_half, False))*(-1) + (calculateHolidays(user, date_splitter, end_day_obj, False, end_half))*(-1) holiday_thisyear = yeardata.days - yeardata.days_inuse - need_days_this days_nextyear_normal = 0 days_nextyear_rest = 0 # Urlaub nächstes Jahr MIT und OHNE Rest if(holiday_nextyear_rest == 0.0): holiday_nextyear = holiday_nextyear - (calculateHolidays(user, date_splitter, end_day_obj, False, end_half))*(-1) else: temprest = holiday_nextyear_rest - need_days_next # Rest reicht! if(temprest >= 0): holiday_nextyear_rest = temprest days_nextyear_normal = 0 days_nextyear_rest = need_days_next # Rest reicht nicht else: holiday_nextyear_rest = 0 holiday_nextyear += temprest days_nextyear_rest = need_days_next + temprest days_nextyear_normal = temprest * -1 # TAGE NORMAL, TAGE NEXT NORMAL, TRUE für 2jahre, TAGE NEXT REST need_days = [need_days_this, days_nextyear_normal, True, days_nextyear_rest] data = [ holiday_thisyear, holiday_lastyear, holiday_nextyear, need_days ] return data def calculateHolidays(user, start, end, start_half, end_half): restdays = 0 allfreedays = FreeDays.objects.filter(agency=user.profile.agency) if(end == start): if(start_half): return restdays - 0.5 else: return restdays - 1 else: if(end < start): return False else: counter = 0 if(start_half): counter -= 0.5 if(end_half): counter -= 0.5 weekdays = [] freedaycounter = 0 for dt in daterange(start, end): day_found = False if dt.isoweekday() not in weekdays: counter += 1 for freeday in allfreedays.all(): if(dt == freeday.day): freedaycounter += 1 day_found = True if day_found == False: if(dt.isoweekday() == 1): if user.usertime.wd_mo == 0.0: freedaycounter += 1 elif(dt.isoweekday() == 2): if user.usertime.wd_tu == 0.0: freedaycounter += 1 elif(dt.isoweekday() == 3): if user.usertime.wd_we == 0.0: freedaycounter += 1 elif(dt.isoweekday() == 4): if user.usertime.wd_th == 0.0: freedaycounter += 1 elif(dt.isoweekday() == 5): if user.usertime.wd_fr == 0.0: freedaycounter += 1 elif(dt.isoweekday() == 6): if user.usertime.wd_sa == 0.0: freedaycounter += 1 elif(dt.isoweekday() == 7): if user.usertime.wd_so == 0.0: freedaycounter += 1 return restdays - counter + freedaycounter # Gibt die Woche als Wochentage zurück def daterange(date1, date2): for n in range(int ((date2 - date1).days)+1): yield date1 + timedelta(n)