2092 lines
74 KiB
Python
2092 lines
74 KiB
Python
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 digitaleagentur.utils import *
|
|
from digitaleagentur.timemanagement_utils import *
|
|
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
|
|
|
|
|
|
|
|
# NC LOGIN
|
|
'''
|
|
|
|
A User has to be logged in in NC. If yes, we check the user-status and retrieving the userId. If the logged user by this session is the same we want to see in Django, than the user will logged in.
|
|
|
|
Double-Check: Logged-Session from NC (session-id cannot be hacked cause it is serverside) and we check userId local, django and NC
|
|
|
|
'''
|
|
import xmltodict, json
|
|
import urllib.request as urllib2
|
|
from django.contrib.auth import login, logout
|
|
from django.core.mail import send_mail
|
|
def ncLogin(request, uid):
|
|
print("HIER PASSIERT DER NCLOGIN" + str(uid))
|
|
#try:
|
|
logout(request)
|
|
if(uid == urllib2.unquote(request.COOKIES['nc_username']) and getNCLoggedUserBySession(request.COOKIES['nc_session_id'])):
|
|
login(request, User.objects.get(username=urllib2.unquote(request.COOKIES['nc_username'])))
|
|
return redirect('users-dashboard')
|
|
return redirect('login')
|
|
#except:
|
|
# return redirect('users-dashboard')
|
|
|
|
|
|
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).exclude(confirm_status=2)
|
|
for ab in absencedays:
|
|
e = Event()
|
|
e.name = ab.user.first_name + " " + ab.user.last_name + " abwesend"
|
|
e.uid = "da-ab-" + str(ab.pk)
|
|
|
|
if ab.start < ab.end:
|
|
e.begin = ab.start
|
|
e.end = ab.end
|
|
else:
|
|
e.begin = ab.start
|
|
e.end = ab.start + timedelta(minutes=1)
|
|
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).exclude(confirm_status=2)
|
|
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)
|
|
|
|
if ab.start < ab.end:
|
|
e.begin = ab.start
|
|
e.end = ab.end
|
|
else:
|
|
e.begin = ab.start
|
|
e.end = ab.start + timedelta(minutes=1)
|
|
|
|
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):
|
|
if(request.method == "GET"):
|
|
#try:
|
|
agency = Agency.objects.get(pk=ag)
|
|
|
|
if agency != None and agency.agencycal_publicstatus == 1 and str(code) == str(agency.agencycalurl):
|
|
c = Calendar()
|
|
absencedays = Absence.objects.filter(agency=ag).exclude(confirm_status=2)
|
|
for ab in absencedays:
|
|
if ab.start != None and ab.end != None:
|
|
e = Event()
|
|
e.name = ab.user.first_name + " " + ab.user.last_name + " abwesend "
|
|
e.uid = "da-ab-" + str(ab.pk)
|
|
|
|
if ab.start < ab.end:
|
|
e.begin = ab.start
|
|
e.end = ab.end
|
|
else:
|
|
e.begin = ab.start
|
|
e.end = ab.start + timedelta(minutes=1)
|
|
#e.allday = True
|
|
c.events.add(e)
|
|
return HttpResponse(c, content_type='text/calendar')
|
|
else:
|
|
realm = ""
|
|
response = HttpResponse()
|
|
response.status_code = 400
|
|
return response
|
|
#except:
|
|
# realm = ""
|
|
# response = HttpResponse()
|
|
# response.status_code = 403
|
|
# return response
|
|
else:
|
|
realm = ""
|
|
response = HttpResponse()
|
|
response.status_code = 404
|
|
return response
|
|
|
|
|
|
|
|
def getICSFileExAll(request, code, ag):
|
|
if(request.method == "GET"):
|
|
#try:
|
|
agency = Agency.objects.get(pk=ag)
|
|
|
|
if agency != None and agency.agencycal_publicstatus == 1 and str(code) == str(agency.agencycalurl_all):
|
|
c = Calendar()
|
|
absencedays = Absence.objects.filter(agency=ag).exclude(confirm_status=2)
|
|
for ab in absencedays:
|
|
if ab.start != None and ab.end != None:
|
|
e = Event()
|
|
e.name = ab.user.first_name + " " + ab.user.last_name + " | " + ab.reason.name
|
|
e.uid = "da-ab-" + str(ab.pk)
|
|
|
|
if ab.start < ab.end:
|
|
e.begin = ab.start
|
|
e.end = ab.end
|
|
else:
|
|
e.begin = ab.start
|
|
e.end = ab.start + timedelta(minutes=1)
|
|
#e.allday = True
|
|
c.events.add(e)
|
|
return HttpResponse(c, content_type='text/calendar')
|
|
else:
|
|
realm = ""
|
|
response = HttpResponse()
|
|
response.status_code = 400
|
|
return response
|
|
#except:
|
|
# realm = ""
|
|
# response = HttpResponse()
|
|
# response.status_code = 403
|
|
# return response
|
|
else:
|
|
realm = ""
|
|
response = HttpResponse()
|
|
response.status_code = 404
|
|
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", "Videoberatung", "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", "Bestellungen", "Büroordnung", "Post", "Technik"]
|
|
|
|
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 = []
|
|
|
|
#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='<p>Hallo lieber DA-Nutzer,</p><p>nicht erschrecken, wir haben für Sie schon einmal eine erste News mit allen wichtigen Informationen rund um diese Anwendung angelegt. </p><h4>Was bietet mir die Digitale Agentur für den Alltag?</h4><p>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:</p><p><iframe frameborder="0" src="//www.youtube.com/embed/rGRZTZlHdEQ" width="640" height="360" class="note-video-clip"></iframe><br></p><h4>Womit fangen Sie nun am besten an?</h4><p>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: <a href="https://digitale-agentur.com/article/erste-schritte/" target="_blank">digitale-agentur.com/article/erste-schritte/</a></p><h4>Wo kann ich mir Hilfe bei Fragen holen?</h4><p>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: <a href="https://digitale-agentur.com/" target="_blank">digitale-agentur.com</a></p><p><span style="font-size: 1rem;">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.</span></p><p>Nun fürs erste aber genug - wir wünschen Ihnen viel Spaß und Erfolg mit der Digitalen Agentur!</p><p>Viele Grüße aus Hamburg ;)<br>Ihr DA-Team</p>')
|
|
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)
|
|
|
|
from adm.models import AGBLog
|
|
|
|
def saveNewAGBLog(byuser, agname, usermail):
|
|
agblog = AGBLog(entry="Agentur von " + byuser + " mit Mail " + usermail + " am " + str(datetime.now()) + " für Agentur " + agname + " erstellt, AGBs und Vertragsdaten akzeptiert.")
|
|
agblog.save()
|
|
|
|
|
|
'''
|
|
|
|
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):
|
|
# AGENTUREGISTRIERUNG
|
|
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()
|
|
|
|
# LOG AGB SAVER
|
|
saveNewAGBLog(newuser_name, agency.name, email)
|
|
|
|
# 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})
|
|
|
|
# LOG AGB SAVER
|
|
saveNewAGBLog(newuser_name, agency.name, email)
|
|
# 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)
|
|
|
|
# Prüfung, ob bei UserTime das Users ein Start drin steht, ansonsten wird dort Einstellungsdatum eingetragen
|
|
if request.user.usertime.usetime_start == None and request.user.usertime.usetime == True:
|
|
request.user.usertime.usetime_start = request.user.usertime.startdate
|
|
request.user.usertime.save()
|
|
#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, delflag = False).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
|
|
|
|
|
|
# Gibt zurück, ob übergebener Nutzer einem anderen Nutzer im Organigramm als Parent zugeordnet ist
|
|
# TRUE - User hat keinen Parent und kann gelöscht werden
|
|
# FALSE - User hat Parent und kann nicht direkt gelöscht werden
|
|
def checkOrgaParent(user):
|
|
returnvalue = True
|
|
for u in User.objects.filter(profile__agency=user.profile.agency):
|
|
if u.profile.parent == user:
|
|
returnvalue = False
|
|
|
|
return returnvalue
|
|
|
|
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, *args, **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)
|
|
'''
|
|
# Standards des Users laden, um diese dann neu zuzuordnen - finaler Löschbutton wird erst angezeigt, wenn alle Standards durchgeklickt wurden (passiert mit AJAX in der HTML)
|
|
usersstandards = []
|
|
agencystandards = Standards.objects.filter(agency=self.request.user.profile.agency)
|
|
|
|
user_to_del = User.objects.get(pk=self.get_object().pk)
|
|
|
|
for s in agencystandards:
|
|
if s.created_standard_by == user_to_del or user_to_del in s.representative.all() or user_to_del in s.executor.all() or user_to_del in s.authority.all() :
|
|
usersstandards.append(s)
|
|
context.update({"standards_to_change" : usersstandards})
|
|
|
|
# Hier werden alle Nutzer der Agentur geladen und in ein Array gepackt, damit diese dann bei den Standards ausgewählt werden können.
|
|
usersofagency = User.objects.filter(profile__agency=user_to_del.profile.agency).exclude(pk=user_to_del.pk)
|
|
context.update({"usersofagency" : usersofagency})
|
|
|
|
context.update({"user_to_del" : user_to_del})
|
|
# Prüft, ob der Nutzer ein Parent im Organigramm ist. Gibt True oder False zurück. Das Template verhindert dann das löschen und informiert den Nutzer.
|
|
context.update({"orgaerror" : checkOrgaParent(kwargs["object"])})
|
|
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()
|
|
'''
|
|
# NC DELETE USER IN NC TOO!
|
|
headers = {
|
|
'Accept' : 'application/json',
|
|
'Access-Control-Allow-Headers' : 'OCS-APIRequest',
|
|
'OCS-APIRequest' : 'true'
|
|
}
|
|
|
|
r = requests.request("DELETE", settings.NEXTCLOUD_URL + "/ocs/v1.php/cloud/users/" + user.username,headers=headers, auth=(settings.NEXTCLOUD_USER_API, settings.NEXTCLOUD_PW_API))
|
|
|
|
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
|
|
|
|
# Saves a new User in parent of others Users.
|
|
@login_required
|
|
def UpdateUserOrga(request):
|
|
if(request.method == "GET"):
|
|
|
|
newuser = User.objects.get(pk=request.GET['userid'])
|
|
olduser = User.objects.get(pk=request.GET['useridold'])
|
|
|
|
if(newuser.profile.agency == request.user.profile.agency and request.user.has_perm("users.usermanager")):
|
|
for u in User.objects.filter(profile__agency=newuser.profile.agency):
|
|
if u.profile.parent != None and u.profile.parent == olduser and newuser != u:
|
|
u.profile.parent = newuser
|
|
u.save()
|
|
# der neue User ist der gleiche wie er selbst - hier den Chef setzen!
|
|
elif u == newuser:
|
|
u.profile.parent = User.objects.filter(profile__agency=newuser.profile.agency).order_by("pk")[0]
|
|
u.save()
|
|
|
|
success = True
|
|
else:
|
|
success = False
|
|
return JsonResponse({"success" : success})
|
|
|
|
|
|
@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()) +'!')
|
|
msg_html = render_to_string('users/supportanswer_mail.html', { 'name' : name, 'text' : problem, 'number' : 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. Ihre Problembeschreibung: " + problem + " - Vielen Dank. Ihr Team der Digitalen Agentur ",'noreply@digitale-agentur.com',[mail],html_message=msg_html,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! Zudem wird gecheckt, ob der Tag tatsächlich Urlaub ist.
|
|
|
|
'''
|
|
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):
|
|
for ab in absencedays:
|
|
if ab.reason.is_time == True:
|
|
returnstat = False
|
|
else:
|
|
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
|
|
if(user.usertime.usetime):
|
|
try:
|
|
workdays = Workday.objects.filter(user=user, end=None, delflag = False)
|
|
for wd in workdays:
|
|
mailstatus += "\n WORKDAY AUTEND ID " + str(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, delflag = False))
|
|
|
|
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
|
|
|
|
day_half_found = False
|
|
if(getAbsenceForOneDay(user, yesterday) != False):
|
|
targettworktime = targettworktime / 2
|
|
day_half_found = True
|
|
|
|
# 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 or day_half_found) and isfreedaycheck(user, yesterday) 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"})
|
|
|
|
mailstatus += " END"
|
|
send_mail(
|
|
'DA-CRON: DAILY',
|
|
mailstatus,
|
|
'noreply@digitale-agentur.com',
|
|
["holger.trampe@vh-solutions.de", "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"],
|
|
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:
|
|
try:
|
|
# 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()
|
|
mailstatus += "\n VOUCHERSTATUS BILL CHANGED TO PAID: " + str(bill.pk)
|
|
elif(json.loads(r.text)["voucherStatus"] == "voided"):
|
|
bill.billstatus="voided"
|
|
bill.save()
|
|
mailstatus += "\n VOUCHERSTATUS BILL CHANGED TO VOIDED: " + str(bill.pk)
|
|
else:
|
|
bill.billstatus="open"
|
|
bill.save()
|
|
|
|
except:
|
|
mailstatus += "\n VOUCHERSTATUS ERROR ON BILL " + str(bill.pk)
|
|
|
|
|
|
# Monatliche Berechnung
|
|
# Alle Rechnungen laden, deren Letzter Tag HEUTE ist und bei ausgewähltem Paymentplan 1 eine neue Rechnung erstellen, Mailverschicken, 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
|
|
# Einen Monat weiter und dann wieder einen Tag zurück
|
|
next_month = today + relativedelta(months=1)
|
|
next_month = next_month - relativedelta(days=1)
|
|
# 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 + relativedelta(days=1)
|
|
start_date_string = start_date.strftime("%d.%m.%Y")
|
|
# Einen Monat weiter und dann wieder einen Tag zurück
|
|
end_date = month + relativedelta(months=1)
|
|
#end_date = end_date - relativedelta(days=1)
|
|
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 += "\n NEW BILL FOR AGENCY " + str(agency.pk)
|
|
except:
|
|
mailstatus += "\n ERROR BY SENDING NEW MAIL TO " + str(agency.pk)
|
|
else:
|
|
data.update({"status" : "failed"})
|
|
|
|
mailstatus += "\n END "
|
|
send_mail(
|
|
'DA-CRON: BILLS',
|
|
mailstatus,
|
|
'noreply@digitale-agentur.com',
|
|
["holger.trampe@vh-solutions.de", "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})
|
|
|