digitaleagenturnc/users/signals.py

623 lines
23 KiB
Python

from django.db.models.signals import post_save, pre_delete, m2m_changed, pre_save
from django.contrib.auth.models import User, Group
from django.dispatch import receiver
from .models import Profile, Agency, AgencyGroup, AgencyNetworkPreperation, UserYearAbsenceInfo, UserTime
from news.models import News
from django.contrib.auth.models import Permission
from notificsys.models import UserNotification
from django.core.mail import send_mail
from django.template.loader import render_to_string
from tasks.models import Tasks
from cloud.models import DataFile
import os
from django.conf import settings
from django.utils import timezone
from standards.models import Standards
from django.contrib.auth.signals import user_logged_in, user_logged_out
from timemanagement.models import Workday, Breaks, AbsenceReason, FreeDays, Absence
from datetime import date
import datetime, json
from django.utils import timezone
import requests, csv, os
from django.templatetags.static import static
from django.conf import settings
from datetime import date
import channels.layers
from asgiref.sync import async_to_sync
from django.contrib.auth.decorators import login_required
from datetime import timedelta
def loadingFreeDays(plz, year):
# Getting land
file_path = os.path.join(settings.STATIC_ROOT, 'users/extra/plz_short.csv')
land = False
with open(file_path, 'rt') as csvfile:
filecsv = csv.reader(csvfile, delimiter=';')
for row in filecsv:
if str(row[1] == str(plz)):
land = row[6]
break;
if(land != False):
URL = "https://feiertage-api.de/api/"
PARAMS = {'jahr':year,'nur_land':land}
r = requests.get(url = URL, params = PARAMS)
return r.json()
else:
return False
# CHECK SOMETHING WHEN USER LOGGED IN
@receiver(signal=user_logged_out, sender=User)
def checkForFreeDays(sender, user, request, **kwargs):
user.profile.onlinestatus = 3
user.save()
# CHECK SOMETHING WHEN USER LOGGED IN
@receiver(signal=user_logged_in, sender=User)
def checkDefaultAbsenceReasons(sender, user, request, **kwargs):
user.profile.onlinestatus = 0
user.save()
ar = AbsenceReason.objects.filter(agency=user.profile.agency)
if(len(ar) == 0):
new_ar_holidays = AbsenceReason(agency=user.profile.agency, name="Urlaub", color="#0099BC", need_confirm=True, need_rep=True, is_holiday=True)
new_ar_holidays.save()
new_ar_specialholidays = AbsenceReason(agency=user.profile.agency, name="Sonderurlaub", need_confirm=True, need_rep=True, is_holiday=False, color="#F39C12")
new_ar_specialholidays.save()
new_ar_ill = AbsenceReason(agency=user.profile.agency, name="Krankheit", color="#E74C3C", need_confirm=False, need_rep=False, is_holiday=False)
new_ar_ill.save()
new_ar_school = AbsenceReason(agency=user.profile.agency, name="Berufsschule", color="#16A085", need_confirm=False, need_rep=False, is_holiday=False)
new_ar_school.save()
new_ar_education = AbsenceReason(agency=user.profile.agency, name="Fortbildung", color="#2ECC71", need_confirm=True, need_rep=True, is_holiday=False)
new_ar_education.save()
today = date.today()
# FREEDAYS LADEN
if len(FreeDays.objects.filter(agency=user.profile.agency, year=today.year+2)) == 0:
tempdays = loadingFreeDays(user.profile.agency.plz, today.year+2)
if(tempdays != False):
for k in tempdays.keys():
tempdate = tempdays[k]["datum"].split("-")
FreeDays(agency=user.profile.agency, name=k, day=datetime.datetime(int(tempdate[0]),int(tempdate[1]),int(tempdate[2])), year=date.today().year+2).save()
# CHECK FOR YEARS
# NO YEARS FOUND
if len(UserYearAbsenceInfo.objects.filter(agency=user.profile.agency)) == 0:
# CREATE DATA FOR EVERY USER
uina = User.objects.filter(profile__agency=user.profile.agency)
for u in uina:
UserYearAbsenceInfo(agency=user.profile.agency, user=u, year=today.year).save()
UserYearAbsenceInfo(agency=user.profile.agency, user=u, year=today.year+1).save()
UserYearAbsenceInfo(agency=user.profile.agency, user=u, year=today.year+2).save()
pass
# CREATE DATE FOR YEAR PLUS 2
elif len(UserYearAbsenceInfo.objects.filter(agency=user.profile.agency, year=today.year+2)) == 0:
uina = User.objects.filter(profile__agency=user.profile.agency)
for u in uina:
UserYearAbsenceInfo(agency=user.profile.agency, user=u, year=today.year+2).save()
'''
class UserYearAbsenceInfo(models.Model):
agency = models.ForeignKey(Agency, on_delete=models.PROTECT, default=None)
user = models.ForeignKey(User, on_delete=models.CASCADE)
year = models.IntegerField()
days = models.FloatField(default=24.0)
restdays = models.FloatField(default=0.0)
'''
'''
wd = Workday.objects.filter(user=user, end=None, start__day__lte=today.day)
for d in wd:
d.end = datetime.datetime(d.start.year, d.start.month, d.start.day, 23, 59, 00)
d.save()
for b in d.breaks.all():
if(b.end == None):
b.end = datetime.datetime(d.start.year, d.start.month, d.start.day, 23, 59, 00)
b.save()
'''
# Deletes all Notifications added to to delete news
@receiver(pre_delete, sender=News)
def del_news_notifications(sender, instance, **kwargs):
UserNotification.objects.filter(elementid=instance.pk).delete()
# SIGNALS FOR USER
'''
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
print(instance)
if created:
Profile.objects.create(user=instance, agency=instance.agency, parent=instance.parent)
#Wenn ein neuer Nutzer angelegt wird und dies der erste der Agentur ist,
#erhält dieser automatisch alle verfügbaren Rechte!
user_agency = User.objects.filter(profile__agency__pk=instance.agency.pk)
if len(user_agency) == 1:
tempuser = user_agency[0]
temprof = Profile
for ele in temprof._meta.permissions:
tempperm = Permission.objects.get(codename=ele[0])
tempuser.user_permissions.add(tempperm)
#tempuser.profile.func = 'lead'
tempuser.save()
'''
@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
# SIGNALS FOR GROUPS
@receiver(signal=m2m_changed, sender=User.groups.through)
def adjust_group_notifications(instance, action, reverse, model, pk_set, using, *args, **kwargs):
# IF FALSE NO MAILS WILL BE SEND - IN PRODUCTIVITY CHANGE TO TRUE #
GLOBALSENDMAILS = True
# GROUPSETTINGS FOR SOME USER WAS CHANGED
if isinstance(instance, Group):
group_touched = AgencyGroup.objects.get(group=instance)
userid = list(pk_set)[0]
user_touched = User.objects.get(pk=userid)
# PUSH NOTIFICATION FOR GROUOPCHANGES
if(user_touched.profile.add_new_group_push):
if(action == 'post_remove'):
newnotification = UserNotification(touser=user_touched, notificationtext="Sie wurden aus der Gruppe " + group_touched.agencygroupname + " entfernt.", notificationtype="groupchanges")
newnotification.save()
# A USER WAS ADDED TO A GROUP
elif(action == 'post_add'):
newnotification = UserNotification(touser=user_touched, notificationtext="Sie wurden zur Gruppe " + group_touched.agencygroupname + " hinzugefügt.", notificationtype="groupchanges")
newnotification.save()
# E-MAILNOTIFICATIONS FOR GROUPCHANGES
if(user_touched.profile.add_new_group_mail):
notificationtext = ""
if(action == 'post_remove'):
notificationtext = "Sie wurden aus der Gruppe " + group_touched.agencygroupname + " entfernt."
username = user_touched.first_name + " " + user_touched.last_name
msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext})
if(GLOBALSENDMAILS):
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
)
# A USER WAS ADDED TO A GROUP
elif(action == 'post_add'):
notificationtext = "Sie wurden zur Gruppe " + group_touched.agencygroupname + " hinzugefügt."
username = user_touched.first_name + " " + user_touched.last_name
msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext})
if(GLOBALSENDMAILS):
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
)
# SIGNAL FOR STANDARDS POST SAVE
@receiver(post_save, sender=Standards)
def save_standard(sender, instance, **kwargs):
GLOBALSENDMAILS = True
# NEW STANDARD AND DIRECT PUBLIC
if(kwargs["created"]):
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
targeturl = settings.BASE_URL + "standards/standard/" + str(instance.pk) + "/single"
if(instance.public):
for user in usersofagency:
if(user.profile.agency_new_standard_mail):
notificationtext = "Neuer Agenturstandard: " + instance.name
username = user.first_name + " " + user.last_name
msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext, 'linktarget' : targeturl})
if(GLOBALSENDMAILS):
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.profile.agency_new_standard_push):
newnotification = UserNotification(touser=user, notificationtext="Neuer Agenturstandard: " + instance.name, notificationtype="newstandard", elementid=instance.pk)
newnotification.save()
else:
for user in usersofagency:
if(user.has_perm("users.standardmanager")):
newnotification = UserNotification(touser=user, notificationtext="Neuer unveröffentlichter Agenturstandard: " + instance.name, notificationtype="newstandard", elementid=instance.pk)
newnotification.save()
else:
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("agency_" + str(instance.agency.pk), {'type' : 'update_standard'})
# SIGNAL FOR NEWS
@receiver(post_save, sender=News)
def save_news(sender, instance, **kwargs):
GLOBALSENDMAILS = True
if(kwargs["created"]):
# Hier wird allen verbundenne Agenturmitgliedern die Info geschickt, dass es neue Agenturnews gibt
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("agency_" + str(instance.agency.pk), {'type' : 'agency_newnews'})
usersofagency = User.objects.filter(profile__agency__pk=instance.agency.pk)
targeturl = settings.BASE_URL + "news/news/" + str(instance.pk) + "/single"
if(instance.go_online_on < timezone.now() and instance.agnotify):
for user in usersofagency:
if(user.profile.news_mail):
notificationtext = "Neue Agenturnews: " + instance.name
username = user.first_name + " " + user.last_name
msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext, 'linktarget' : targeturl})
if(GLOBALSENDMAILS):
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.profile.news_push):
newnotification = UserNotification(touser=user, notificationtext="Neue Agenturnews: " + instance.name, notificationtype="agencynews", elementid=instance.pk)
newnotification.save()
else:
instance.agnotify = False
instance.save()
else:
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("agency_" + str(instance.agency.pk), {'type' : 'agency_newnews'})
# SIGNALS FOR TASK
@receiver(signal=m2m_changed, sender=Tasks.usersfield.through)
def adjust_group_notifications_task(instance, action, reverse, model, pk_set, using, *args, **kwargs):
# IF FALSE NO MAILS WILL BE SEND - IN PRODUCTIVITY CHANGE TO TRUE #
GLOBALSENDMAILS = True
# A USER WAS TOUCHED ATT HIS TASKS
user_touched = User.objects.get(pk=list(pk_set)[0])
taskname = instance.name
# PUSH NOTIFICATION FOR GROUOPCHANGES
if(user_touched.profile.add_task_push):
if(action == 'post_remove'):
newnotification = UserNotification(touser=user_touched, notificationtext="Sie wurden von der Tätigkeit " + taskname + " entfernt.", notificationtype="taskchange")
newnotification.save()
# A USER WAS ADDED TO A GROUP
elif(action == 'post_add'):
newnotification = UserNotification(touser=user_touched, notificationtext="Sie wurden der Tätigkeit " + taskname + " zugeordnet.", notificationtype="taskchange")
newnotification.save()
# E-MAILNOTIFICATIONS FOR GROUPCHANGES
if(user_touched.profile.add_task_mail):
notificationtext = ""
if(action == 'post_remove'):
notificationtext = "Sie wurden von der Tätigkeit " + taskname + " entfernt."
username = user_touched.first_name + " " + user_touched.last_name
msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext})
if(GLOBALSENDMAILS):
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
)
# A USER WAS ADDED TO A GROUP
elif(action == 'post_add'):
notificationtext = "Sie wurden der Tätigkeit " + taskname + " zugeordnet."
username = user_touched.first_name + " " + user_touched.last_name
msg_html = render_to_string('notificsys/notification_mail.html', {'username': username, 'notificationtext' : notificationtext})
if(GLOBALSENDMAILS):
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
)
@receiver(signal=post_save, sender=AgencyNetworkPreperation)
def save_agjoin_prep(sender, instance, **kwargs):
newnotification = UserNotification(touser=instance.target_network.creator, notificationtext="Eine Agentur möchte Ihrem Verbund beitreten.", notificationtype="wantedag", elementid=instance.pk)
newnotification.save()
from django.core.signals import request_started
from channels_presence.models import Room
from channels_presence.models import Presence
from channels_presence.signals import presence_changed
# REQUEST MAIN STUFF
@receiver(signal=request_started)
def receiver_function(sender, **kwargs):
# DELETES ALL PRESENCE-OBJETS LOWER THAN 15 MINUTES
now_minus = datetime.datetime.now() - datetime.timedelta(minutes=2)
Presence.objects.filter(last_seen__lt=now_minus).delete()
# PREENCE CHANGED
@receiver(signal=presence_changed)
def update_presence_live(sender, **kwargs):
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)(str(kwargs["room"]), {'type' : 'update_presence_live'})
'''
ABWESENHEIT BERECHNUNG UND SPEICHERUNG DER NEUEN URLAUBSTAGE - VERWEIS AUF timemenagement.views
'''
@receiver(signal=post_save, sender=Absence)
def save_newabsence(sender, instance, **kwargs):
post_save.disconnect(save_newabsence, sender=sender)
if(instance.reason.is_holiday):
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.save()
# Hier werd der REST als vorjahreswert und NORMAL als nächstes Jahr gespeichert
instance.holidays_normal = newdata[3][1]
instance.holidays_rest = newdata[3][0]
instance.save()
else:
print("Absence-Object is no holiday...")
post_save.connect(save_newabsence, sender=sender)
@receiver(signal=pre_delete, sender=Absence)
def delete_absence(sender, instance, **kwargs):
if(instance.reason.is_holiday):
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
print(newdata)
if(instance.start.year != instance.end.year):
abinfo.days_inuse = abinfo.days_inuse - instance.holidays_rest
abinfo.save()
abinfo_nextyear.days_inuse = abinfo_nextyear.days_inuse - instance.holidays_normal
abinfo_nextyear.save()
else:
# Gleiches Jahr MIT Rest
abinfo.days_inuse = abinfo.days_inuse - instance.holidays_normal
abinfo.restdays = abinfo.restdays + instance.holidays_rest
abinfo.save()
else:
print("Absence-Object is no holiday...")
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
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
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:
holiday_lastyear = yeardata.restdays
date_splitter = datetime.date(end_day_obj.year, 1, 1)
#days_next_year = end_day_obj - date_splitter_postyear
#days_this_year = date_splitter_preyear - start_day_obj
need_days = [(calculateHolidays(user, start_day_obj, date_splitter, start_half, False))*(-1), (calculateHolidays(user, date_splitter, end_day_obj, False, end_half))*(-1), True]
holiday_thisyear = yeardata.days - yeardata.days_inuse - (calculateHolidays(user, start_day_obj, date_splitter, start_half, False))*(-1)
holiday_nextyear = holiday_nextyear - (calculateHolidays(user, date_splitter, end_day_obj, False, end_half))*(-1)
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 = [6,7]
freedaycounter = 0
for dt in daterange(start, end):
if dt.isoweekday() not in weekdays:
counter += 1
for freeday in allfreedays.all():
if(dt == freeday.day):
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)