Auditlog und Adminoberfläche, Druckersymbol Standard und Bug in der Navigation

This commit is contained in:
holger.trampe 2021-01-08 09:32:02 +01:00
parent ef493e0da4
commit bbf66dc731
21 changed files with 131 additions and 26 deletions

View File

@ -3,6 +3,8 @@
{% load adm_tags %} {% load adm_tags %}
<div class="content-section col-12"> <div class="content-section col-12">
<h4>Agenturübersicht</h4> <h4>Agenturübersicht</h4>
{% loadAboCount as abocount %}
<small>Aktive Abos: {{abocount}}</small>
<hr> <hr>
<table class="table table-hover" id="agdata" > <table class="table table-hover" id="agdata" >
<thead> <thead>

View File

@ -67,5 +67,10 @@
}); });
}) })
</script> </script>
<hr>
<h5>Logins (letzten 50)</h5>
{% for ele in logdata %}
{{forloop.counter}}. {{ele|date:"d.m.Y, H:i"}}<br />
{% endfor %}
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -37,3 +37,6 @@ def getlaststat():
def getAgencyGroupName(group): def getAgencyGroupName(group):
return AgencyGroup.objects.get(group=group) return AgencyGroup.objects.get(group=group)
@register.simple_tag
def loadAboCount():
return len(Agency.objects.filter(paymentplan=1))

View File

@ -10,7 +10,10 @@ from chat.models import ChatMessage
from users.models import Agency, AgencyBills, RegNotfallhilfe from users.models import Agency, AgencyBills, RegNotfallhilfe
from standards.models import Standards from standards.models import Standards
import csv import csv
from datetime import date from auditlog.models import LogEntry
from datetime import date, datetime
import json
''' '''
Prüfung, ob angemeldeter User Mitarbeiterstatus hat. IMMER PER DISPATCH EINBAUEN! Prüfung, ob angemeldeter User Mitarbeiterstatus hat. IMMER PER DISPATCH EINBAUEN!
''' '''
@ -195,6 +198,21 @@ class AdmUserSingle(TemplateView):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context.update({'active_link' : "adm-users"}) context.update({'active_link' : "adm-users"})
context.update({'userdata' : User.objects.get(pk=kwargs['uspk'])}) context.update({'userdata' : User.objects.get(pk=kwargs['uspk'])})
# Loading Logindata
logdata = LogEntry.objects.filter(object_pk=kwargs['uspk'])[:50]
logdata_logins = []
for ele in logdata:
datestring = json.loads(ele.changes)["last_login"][1]
datestring = datestring.split(".")[0]
logdata_logins.append(datetime.strptime(datestring, '%Y-%m-%d %H:%M:%S'))
context.update({'logdata' : logdata_logins})
return context return context

View File

@ -93,10 +93,9 @@ INSTALLED_APPS = [
'channels_presence', 'channels_presence',
'simple_history', 'simple_history',
'captcha', 'captcha',
'auditlog',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
@ -107,6 +106,7 @@ MIDDLEWARE = [
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django_user_agents.middleware.UserAgentMiddleware', 'django_user_agents.middleware.UserAgentMiddleware',
'simple_history.middleware.HistoryRequestMiddleware', 'simple_history.middleware.HistoryRequestMiddleware',
'auditlog.middleware.AuditlogMiddleware'
] ]
ROOT_URLCONF = 'digitaleagentur.urls' ROOT_URLCONF = 'digitaleagentur.urls'

BIN
dump.rdb

Binary file not shown.

View File

@ -14,6 +14,9 @@
<h2>{{standard.name}} <h2>{{standard.name}}
<span style="float: right"> <span style="float: right">
<a href="{% url 'ajax-standardpdf' standard.pk %}" target="_blank" style="margin-top: -4px;" class="btn btn-primary btn-sm mr-2" onclick="javascript:printStandard()">
<i class="fas fa-print"></i>
</a>
{% if standard.created_standard_by != null and standard.created_standard_by == user or perms.users.standardmanager %} {% if standard.created_standard_by != null and standard.created_standard_by == user or perms.users.standardmanager %}
<a style="float: right" class="btn btn-secondary btn-sm ml-2" href="{% url 'standard-delete' standard.pk %}"><small><i class="fas fa-trash"></i></small></a> <a style="float: right" class="btn btn-secondary btn-sm ml-2" href="{% url 'standard-delete' standard.pk %}"><small><i class="fas fa-trash"></i></small></a>
<a style="float: right" class="btn btn-secondary btn-sm " href="{% url 'standard-add' standard.pk %}"><small><i class="fas fa-pen"></i></small></a> <a style="float: right" class="btn btn-secondary btn-sm " href="{% url 'standard-add' standard.pk %}"><small><i class="fas fa-pen"></i></small></a>
@ -222,11 +225,6 @@
{% endif %} {% endif %}
</div> </div>
<div class="mt-2"> <div class="mt-2">
<a href="{% url 'ajax-standardpdf' standard.pk %}" target="_blank" class="btn btn-primary btn-sm mr-2" onclick="javascript:printStandard()">
<i class="fas fa-print"></i>
</a>
<small> <small>
{% if not standard.created_standard_by %} Erstellt von gelöschtem Mitarbeiter {% else %} Erstellt durch <a href="{% url 'orga-single' standard.created_standard_by.pk %}">{{standard.created_standard_by.first_name}} {{standard.created_standard_by.last_name}}</a> {% endif %} am {{standard.created_standard_date}} | {% if not standard.last_modified_by %} Zuletzt bearbeitet von gelöschtem Benutzer {% else %} Zuletzt bearbeitet von <a href="{% url 'orga-single' standard.last_modified_by.pk %}">{{ standard.last_modified_by.first_name}} {{ standard.last_modified_by.last_name}}</a>{% endif %} am {{ standard.last_modified_on}} {% if not standard.created_standard_by %} Erstellt von gelöschtem Mitarbeiter {% else %} Erstellt durch <a href="{% url 'orga-single' standard.created_standard_by.pk %}">{{standard.created_standard_by.first_name}} {{standard.created_standard_by.last_name}}</a> {% endif %} am {{standard.created_standard_date}} | {% if not standard.last_modified_by %} Zuletzt bearbeitet von gelöschtem Benutzer {% else %} Zuletzt bearbeitet von <a href="{% url 'orga-single' standard.last_modified_by.pk %}">{{ standard.last_modified_by.first_name}} {{ standard.last_modified_by.last_name}}</a>{% endif %} am {{ standard.last_modified_on}}
</small> </small>

View File

@ -75,6 +75,11 @@ def getWorkDayHistory(workday):
workday = Workday.objects.get(pk=workday.pk) workday = Workday.objects.get(pk=workday.pk)
return workday.history.first() return workday.history.first()
# Last Absence
@register.simple_tag
def getLastEditedAbsence(absence):
return Absence.objects.get(pk=absence.pk).history.first()
# usergperm # usergperm
''' '''

View File

@ -68,7 +68,7 @@ class Absence(models.Model):
holidays_rest = models.FloatField(default=0.0, max_length=9, blank=True) holidays_rest = models.FloatField(default=0.0, max_length=9, blank=True)
holidays_normal_next = models.FloatField(default=0.0, max_length=9, blank=True) holidays_normal_next = models.FloatField(default=0.0, max_length=9, blank=True)
holidays_rest_next = models.FloatField(default=0.0, max_length=9, blank=True) holidays_rest_next = models.FloatField(default=0.0, max_length=9, blank=True)
history = HistoricalRecords()
class FreeDays(models.Model): class FreeDays(models.Model):
agency = models.ForeignKey(Agency, on_delete=models.CASCADE) agency = models.ForeignKey(Agency, on_delete=models.CASCADE)

View File

@ -22,7 +22,7 @@
<td>{{abday.end|date:"d.M Y"}}</td> <td>{{abday.end|date:"d.M Y"}}</td>
<td>{{abday.reason.name}}</td> <td>{{abday.reason.name}}</td>
<td>{{abday.info}}</td> <td>{{abday.info}}</td>
<td>{% if abday.confirm_status == 0 %} Genehmigt {% elif abday.confirm_status == 1 %} Beantragt {% else %} Abgelehnt {% endif %}</td> <td style="text-align: center;">{% if abday.confirm_status == 0 %} <i class="far fa-check-circle" style="color: green"></i> {% elif abday.confirm_status == 1 %} Beantragt {% else %} <i class="far fa-times-circle" style="color: red"></i> {% endif %}</td>
<td style="float: right !important; min-width: 100%"> <td style="float: right !important; min-width: 100%">
<button type="button" style="float: right; margin-left: 2px;" class="btn btn-secondary btn-sm" onclick="javascript:$('#confirm-delete_{{abday.pk}}').modal('toggle')"><i class="fas fa-trash"></i></button> <button type="button" style="float: right; margin-left: 2px;" class="btn btn-secondary btn-sm" onclick="javascript:$('#confirm-delete_{{abday.pk}}').modal('toggle')"><i class="fas fa-trash"></i></button>
<button type="button " style="float: right" class="btn btn-secondary btn-sm mr-1" onclick="javascript:changeAbsence({{abday.pk}})"><i class="fas fa-pen"></i></button> <button type="button " style="float: right" class="btn btn-secondary btn-sm mr-1" onclick="javascript:changeAbsence({{abday.pk}})"><i class="fas fa-pen"></i></button>

View File

@ -8,6 +8,11 @@
<div class="content-section col-8"> <div class="content-section col-8">
<h3>Abwesenheit von {{absence.user.first_name}} {{absence.user.last_name}} Bearbeiten</h3> <h3>Abwesenheit von {{absence.user.first_name}} {{absence.user.last_name}} Bearbeiten</h3>
{% getLastEditedAbsence absence as absencehistorie %}
{% if absencehistorie.history_user != None %}
<small>Zuletzt bearbeitet von {{absencehistorie.history_user.first_name}} {{absencehistorie.history_user.last_name}} am {{absencehistorie.history_date|date:"d.m.Y, H:i"}}</small>
{% endif %}
<hr> <hr>
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-6">

View File

@ -59,8 +59,9 @@
<th scope="col">Start</th> <th scope="col">Start</th>
<th scope="col">Ende</th> <th scope="col">Ende</th>
<th scope="col">Grund</th> <th scope="col">Grund</th>
<th scope="col">Status</th> <th scope="col">Antrag</th>
<th scope="col">Begründung</th> <th scope="col">Begründung</th>
<th scope="col">Status</th>
</tr> </tr>
</thead> </thead>
<tbody id=""> <tbody id="">
@ -69,8 +70,9 @@
<td>{{abday.start|date:"d.M Y"}}</td> <td>{{abday.start|date:"d.M Y"}}</td>
<td>{{abday.end|date:"d.M Y"}}</td> <td>{{abday.end|date:"d.M Y"}}</td>
<td>{{abday.reason.name}}</td> <td>{{abday.reason.name}}</td>
<td>{% if abday.confirm_status == 0 %} Genehmigt {% elif abday.confirm_status == 1 %} Beantragt {% else %} Abgelehnt {% endif %}</td> <td>{{abday.info}}</td>
<td>{{abday.confirm_info}}</td> <td>{{abday.confirm_info}}</td>
<td style="text-align: center;">{% if abday.confirm_status == 0 %} <i class="far fa-check-circle" style="color: green"></i> {% elif abday.confirm_status == 1 %} Beantragt {% else %} <i class="far fa-times-circle" style="color: red"></i> {% endif %}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

@ -7,7 +7,7 @@ from django.utils import timezone
from django.contrib.auth.models import User, Group, Permission from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
import datetime import datetime
from simple_history.models import HistoricalRecords
# UNIQUE and NO BLANK fields while user-registration # UNIQUE and NO BLANK fields while user-registration
User._meta.get_field('email')._unique = True User._meta.get_field('email')._unique = True
User._meta.get_field('email').blank = False User._meta.get_field('email').blank = False
@ -515,15 +515,26 @@ class RegNotfallhilfe(models.Model):
wassend = models.BooleanField(default=False) wassend = models.BooleanField(default=False)
orderdate = models.DateField(default=timezone.now, null=True) orderdate = models.DateField(default=timezone.now, null=True)
# SUBCLASS # SUBCLASS
class UserFullName(User): class UserFullName(User):
class Meta:
proxy = True
def __unicode__(self): history = HistoricalRecords()
return "placeholder"
class Meta:
proxy = True
def __unicode__(self):
return "placeholder"
def __str__(self):
return f'{self.first_name + " " + self.last_name}'
# Hier Audit-Logeinträge einbauen für die versch. Models
from django.utils.six import python_2_unicode_compatible
from auditlog.registry import auditlog
auditlog.register(User)
auditlog.register(Agency)
def __str__(self):
return f'{self.first_name + " " + self.last_name}'

View File

@ -305,7 +305,7 @@
<a style="color: #999; text-decoration: none;" href="https://digitale-agentur.com/impressum" target="_blank">Impressum</a> <a style="color: #999; text-decoration: none;" href="https://digitale-agentur.com/impressum" target="_blank">Impressum</a>
<br /> <br />
<br /> <br />
Version 1.0.2 Version 1.0.3
<br /> <br />
<br /> <br />
<a href="https://www.myvve.de/" target="_blank"><img src="{% static 'users/img/VVE-Logo.png' %}" width="27%" class="mb-2"></a> <a href="https://www.myvve.de/" target="_blank"><img src="{% static 'users/img/VVE-Logo.png' %}" width="27%" class="mb-2"></a>
@ -517,6 +517,10 @@
<i class="fas fa-bell fa-sm fa-fw mr-2 text-gray-400"></i> <i class="fas fa-bell fa-sm fa-fw mr-2 text-gray-400"></i>
Benachrichtigungen Benachrichtigungen
</a> </a>
<a class="dropdown-item" href="{% url 'users-log' request.user.pk %}">
<i class="fas fa-bell fa-sm fa-fw mr-2 text-gray-400"></i>
Anmeldevorgänge
</a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'users-logout' %}"> <a class="dropdown-item" href="{% url 'users-logout' %}">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i> <i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
@ -672,9 +676,8 @@ $(document).ready(function(){
// Toggle the side navigation // Toggle the side navigation
function toggleSidebar(){ function toggleSidebar(){
if(sidebar_hidden == false){ if(sidebar_hidden == false){
$("#accordionSidebar").addClass("toggled"); $("#accordionSidebar").removeClass("toggled");
$("#content-wrapper").css("margin-left" , "105px"); $("#content-wrapper").css("margin-left" , "105px");
$("#topnavbarmain").css("margin-left" , "105px"); $("#topnavbarmain").css("margin-left" , "105px");
@ -682,7 +685,7 @@ function toggleSidebar(){
sidebar_hidden = true; sidebar_hidden = true;
} }
else{ else{
$("#accordionSidebar").removeClass("toggled"); $("#accordionSidebar").addClass("toggled");
$("#content-wrapper").css("margin-left" , "0px"); $("#content-wrapper").css("margin-left" , "0px");
$("#topnavbarmain").css("margin-left" , "0px"); $("#topnavbarmain").css("margin-left" , "0px");
sidebar_hidden = false; sidebar_hidden = false;

View File

@ -7,7 +7,7 @@
<small>Letzter Login: {{ request.user.last_login }} <small>Letzter Login: {{ request.user.last_login }}
{% getlocalweather request.user as weatherdata %} {% getlocalweather request.user as weatherdata %}
{% if request.user.profile.agency.city|length > 0 and weatherdata.0 != None %} {% if request.user.profile.agency.city|length > 0 and weatherdata.0 != None %}
{{weatherdata.0}}<img src='https://openweathermap.org/img/wn/{{weatherdata.1}}.png' width="45px" style="margin-bottom: -5px; padding-right: -20px; margin-left: -10px; margin-top: -15px; margin-right: -6px;">{{weatherdata.2}}</small> {{weatherdata.0}}&nbsp;<img src='https://openweathermap.org/img/wn/{{weatherdata.1}}.png' width="45px" style="margin-bottom: -5px; padding-right: -20px; margin-left: -10px; margin-top: -15px; margin-right: -6px;">&nbsp;{{weatherdata.2}}</small>
{% endif %} {% endif %}
<hr> <hr>
<h5>Agentur: <b>{{ request.user.profile.agency.name }}</b></h5> <h5>Agentur: <b>{{ request.user.profile.agency.name }}</b></h5>

View File

@ -0,0 +1,12 @@
{% extends "users/base.html" %}
{% load counter_tag %}
{% block content %}
<div class="content-section col-12">
<h3>Anmeldelog</h3>
<small>Hier sehen Sie eine Auflistung Ihrer letzten 50 Anmeldevorgänge.</small>
<hr>
{% for ele in logdata %}
{{forloop.counter}}. Login am {{ele|date:"d.m.Y, H:i"}}<br />
{% endfor %}
</div>
{% endblock %}

View File

@ -24,6 +24,7 @@ urlpatterns = [
path('usersman/<int:pk>/perms', permission_required('users.usermanager')(UsersPermUpdateView.as_view()), name='users-perm-update'), path('usersman/<int:pk>/perms', permission_required('users.usermanager')(UsersPermUpdateView.as_view()), name='users-perm-update'),
path('usersman/<int:pk>/delete', permission_required('users.usermanager')(ProfileDeleteView.as_view()), name='users-delete'), path('usersman/<int:pk>/delete', permission_required('users.usermanager')(ProfileDeleteView.as_view()), name='users-delete'),
path('usersman/gd/<int:pk>', views.getDataFromToDelUser, name="users-delete-getdata"), path('usersman/gd/<int:pk>', views.getDataFromToDelUser, name="users-delete-getdata"),
path('userlog/<int:pk>', views.showUserLog, name="users-log"),
#path('agencyinfo/', views.agency, name='agencyinfo'), #path('agencyinfo/', views.agency, name='agencyinfo'),
#path('agencyinfo/<int:pk>/', permission_required('users.agency_change')(AgencyUpdateView.as_view()), name='agency-manage'), #path('agencyinfo/<int:pk>/', permission_required('users.agency_change')(AgencyUpdateView.as_view()), name='agency-manage'),
path('usersman/<int:pk>/prio', views.UsersPrio, name='users-prio'), path('usersman/<int:pk>/prio', views.UsersPrio, name='users-prio'),

View File

@ -636,10 +636,50 @@ class AgencyCreateView(CreateView):
return super().form_valid(form) return super().form_valid(form)
#from django.core.mail import EmailMessage
#from django.core.mail import EmailMultiAlternatives
from auditlog.models import LogEntry
@login_required
def showUserLog(request, pk):
logdata = LogEntry.objects.filter(object_pk=request.user.pk)[:50]
logdata_logins = []
for ele in logdata:
datestring = json.loads(ele.changes)["last_login"][1]
datestring = datestring.split(".")[0]
logdata_logins.append(datetime.strptime(datestring, '%Y-%m-%d %H:%M:%S'))
context = {
'logdata' : logdata_logins
}
return render(request, 'users/userlog.html', context)
@login_required @login_required
def dashboard(request): def dashboard(request):
# UPDATE FUNCTIONS BY NEW MODEL-CHANGES FOR COPIEN SOME DATA # UPDATE FUNCTIONS BY NEW MODEL-CHANGES FOR COPIEN SOME DATA
toUpdate(request) toUpdate(request)
'''
# BCC Mail with Object - NICHT DEN IMPORT VERGESSEN!!!
email = EmailMultiAlternatives(
'Subject',
'Bitte aktivieren Sie HTML in Ihrem Mailprogramm.',
'noreply@digitale-agentur.com',
['mail@holgertrampe.de'],
['htrampe@gmail.com'],
#reply_to=['noreply@digitale-agentur.com'],
headers={},
)
email.attach_alternative("<html><body><h1>Lobbt der Shit!</h1><hr></body></html>", "text/html")
email.send()
'''
#storageinfo = sys.getfilesystemencoding() #storageinfo = sys.getfilesystemencoding()